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

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


The following commit(s) were added to refs/heads/feat#7280 by this push:
     new cb840c58a feat: add deployment metadata to the table of the 'DORA 
details - deployment frequency' dashboard
cb840c58a is described below

commit cb840c58abb1d9a73d718fa1eae8a83bfbe47263
Author: abeizn <[email protected]>
AuthorDate: Mon Apr 15 16:04:28 2024 +0800

    feat: add deployment metadata to the table of the 'DORA details - 
deployment frequency' dashboard
---
 .../models/domainlayer/devops/cicd_deployment.go   |  2 +
 .../domainlayer/devops/cicd_deployment_commit.go   |  4 ++
 .../models/domainlayer/devops/cicd_pipeline.go     |  5 +-
 .../domainlayer/devops/cicd_pipeline_commmit.go    | 14 ++--
 ...0410_add_display_title_and_url_to_deployment.go | 77 ++++++++++++++++++++++
 backend/core/models/migrationscripts/register.go   |  1 +
 .../20240411_add_link_href_to_plan_build.go        | 55 ++++++++++++++++
 .../bamboo/models/migrationscripts/register.go     |  1 +
 backend/plugins/bamboo/models/plan_build.go        |  8 ++-
 backend/plugins/bamboo/models/plan_build_commit.go |  2 +
 .../deploy_build_to_deployment_commit_convertor.go | 10 +--
 .../tasks/deploy_build_to_deployment_convertor.go  |  1 +
 .../plugins/bamboo/tasks/plan_build_convertor.go   | 13 +++-
 .../plugins/bamboo/tasks/plan_build_extractor.go   | 10 +++
 .../plugins/bamboo/tasks/plan_commit_convertor.go  |  6 +-
 .../bitbucket/tasks/deployment_convertor.go        | 12 ++--
 .../plugins/bitbucket/tasks/pipeline_convertor.go  | 18 +++--
 .../plugins/bitbucket/tasks/pipeline_extractor.go  |  3 -
 .../plugins/circleci/tasks/workflow_converter.go   | 17 +++--
 .../dora/tasks/deployment_commits_generator.go     |  2 +
 backend/plugins/dora/tasks/deployment_generator.go |  2 +
 backend/plugins/github/models/deployment.go        |  8 ++-
 .../20240410_add_workflow_display_title.go         | 55 ++++++++++++++++
 .../github/models/migrationscripts/register.go     |  1 +
 backend/plugins/github/models/run.go               |  4 +-
 backend/plugins/github/tasks/cicd_run_convertor.go | 12 ++--
 .../plugins/github/tasks/deployment_convertor.go   | 10 +--
 .../github_graphql/tasks/deployment_collector.go   | 14 ++++
 .../github_graphql/tasks/deployment_extractor.go   |  3 +
 .../20240411_add_web_url_to_pipeline.go}           | 41 +++++++-----
 .../gitlab/models/migrationscripts/register.go     |  1 +
 backend/plugins/gitlab/models/pipeline.go          |  1 +
 .../plugins/gitlab/tasks/deployment_convertor.go   |  2 +
 .../gitlab/tasks/pipeline_commit_convertor.go      |  2 +
 .../gitlab/tasks/pipeline_detail_convertor.go      |  2 +
 .../gitlab/tasks/pipeline_detail_extractor.go      |  3 -
 backend/plugins/gitlab/tasks/pipeline_extractor.go |  1 +
 .../plugins/azuredevops/azuredevops/migrations.py  |  6 ++
 .../plugins/azuredevops/azuredevops/models.py      |  2 +
 .../azuredevops/azuredevops/streams/builds.py      |  4 ++
 .../pydevlake/pydevlake/domain_layer/devops.py     |  5 ++
 41 files changed, 369 insertions(+), 71 deletions(-)

diff --git a/backend/core/models/domainlayer/devops/cicd_deployment.go 
b/backend/core/models/domainlayer/devops/cicd_deployment.go
index 199e95fa2..b30710772 100644
--- a/backend/core/models/domainlayer/devops/cicd_deployment.go
+++ b/backend/core/models/domainlayer/devops/cicd_deployment.go
@@ -25,6 +25,8 @@ type CICDDeployment struct {
        domainlayer.DomainEntity
        CicdScopeId         string `gorm:"index;type:varchar(255)"`
        Name                string `gorm:"type:varchar(255)"`
+       DisplayTitle        string
+       Url                 string
        Result              string `gorm:"type:varchar(100)"`
        Status              string `gorm:"type:varchar(100)"`
        OriginalStatus      string `gorm:"type:varchar(100)"`
diff --git a/backend/core/models/domainlayer/devops/cicd_deployment_commit.go 
b/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
index aa8b9db8d..7b24cee6b 100644
--- a/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
+++ b/backend/core/models/domainlayer/devops/cicd_deployment_commit.go
@@ -26,6 +26,8 @@ type CicdDeploymentCommit struct {
        CicdScopeId         string `gorm:"index;type:varchar(255)"`
        CicdDeploymentId    string `gorm:"type:varchar(255)"` // if it is 
converted from a cicd_pipeline_commit
        Name                string `gorm:"type:varchar(255)"`
+       DisplayTitle        string
+       Url                 string
        Result              string `gorm:"type:varchar(100)"`
        Status              string `gorm:"type:varchar(100)"`
        OriginalStatus      string `gorm:"type:varchar(100)"`
@@ -70,5 +72,7 @@ func (cicdDeploymentCommit CicdDeploymentCommit) 
ToDeployment() *CICDDeployment
                },
                QueuedDurationSec: cicdDeploymentCommit.QueuedDurationSec,
                DurationSec:       cicdDeploymentCommit.DurationSec,
+               DisplayTitle:      cicdDeploymentCommit.DisplayTitle,
+               Url:               cicdDeploymentCommit.Url,
        }
 }
diff --git a/backend/core/models/domainlayer/devops/cicd_pipeline.go 
b/backend/core/models/domainlayer/devops/cicd_pipeline.go
index d8748e39a..e05d573b6 100644
--- a/backend/core/models/domainlayer/devops/cicd_pipeline.go
+++ b/backend/core/models/domainlayer/devops/cicd_pipeline.go
@@ -18,15 +18,18 @@ limitations under the License.
 package devops
 
 import (
-       "github.com/spf13/cast"
        "strings"
 
+       "github.com/spf13/cast"
+
        "github.com/apache/incubator-devlake/core/models/domainlayer"
 )
 
 type CICDPipeline struct {
        domainlayer.DomainEntity
        Name              string `gorm:"type:varchar(255)"`
+       DisplayTitle      string
+       Url               string
        Result            string `gorm:"type:varchar(100)"`
        Status            string `gorm:"type:varchar(100)"`
        OriginalStatus    string `gorm:"type:varchar(100)"`
diff --git a/backend/core/models/domainlayer/devops/cicd_pipeline_commmit.go 
b/backend/core/models/domainlayer/devops/cicd_pipeline_commmit.go
index 10e0dac57..bbf8f18fa 100644
--- a/backend/core/models/domainlayer/devops/cicd_pipeline_commmit.go
+++ b/backend/core/models/domainlayer/devops/cicd_pipeline_commmit.go
@@ -23,12 +23,14 @@ import (
 
 type CiCDPipelineCommit struct {
        common.NoPKModel
-       PipelineId string `gorm:"primaryKey;type:varchar(255)"`
-       CommitSha  string `gorm:"primaryKey;type:varchar(255)"`
-       CommitMsg  string
-       Branch     string `gorm:"type:varchar(255)"`
-       RepoId     string `gorm:"index;type:varchar(255)"`
-       RepoUrl    string
+       PipelineId   string `gorm:"primaryKey;type:varchar(255)"`
+       CommitSha    string `gorm:"primaryKey;type:varchar(255)"`
+       CommitMsg    string
+       DisplayTitle string
+       Url          string
+       Branch       string `gorm:"type:varchar(255)"`
+       RepoId       string `gorm:"index;type:varchar(255)"`
+       RepoUrl      string
 }
 
 func (CiCDPipelineCommit) TableName() string {
diff --git 
a/backend/core/models/migrationscripts/20240410_add_display_title_and_url_to_deployment.go
 
b/backend/core/models/migrationscripts/20240410_add_display_title_and_url_to_deployment.go
new file mode 100644
index 000000000..66876cb26
--- /dev/null
+++ 
b/backend/core/models/migrationscripts/20240410_add_display_title_and_url_to_deployment.go
@@ -0,0 +1,77 @@
+/*
+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"
+       "github.com/apache/incubator-devlake/helpers/migrationhelper"
+)
+
+var _ plugin.MigrationScript = (*addDisplayTitleAndUrl)(nil)
+
+type cicdDeployment20240410 struct {
+       DisplayTitle string
+       Url          string
+}
+
+func (cicdDeployment20240410) TableName() string {
+       return "cicd_deployments"
+}
+
+type cicdDeploymentCommit20240410 struct {
+       DisplayTitle string
+       Url          string
+}
+
+func (cicdDeploymentCommit20240410) TableName() string {
+       return "cicd_deployment_commits"
+}
+
+type cicdPipeline20240410 struct {
+       DisplayTitle string
+       Url          string
+}
+
+func (cicdPipeline20240410) TableName() string {
+       return "cicd_pipelines"
+}
+
+type cicdPipelineCommit20240410 struct {
+       DisplayTitle string
+       Url          string
+}
+
+func (cicdPipelineCommit20240410) TableName() string {
+       return "cicd_pipeline_commits"
+}
+
+type addDisplayTitleAndUrl struct{}
+
+func (*addDisplayTitleAndUrl) Up(basicRes context.BasicRes) errors.Error {
+       return migrationhelper.AutoMigrateTables(basicRes, 
&cicdDeployment20240410{}, &cicdDeploymentCommit20240410{}, 
&cicdPipeline20240410{}, &cicdPipelineCommit20240410{})
+}
+
+func (*addDisplayTitleAndUrl) Version() uint64 {
+       return 20240410111248
+}
+
+func (*addDisplayTitleAndUrl) Name() string {
+       return "add display title and url to deployments and pipelines"
+}
diff --git a/backend/core/models/migrationscripts/register.go 
b/backend/core/models/migrationscripts/register.go
index f4641d03b..3c3e2e45f 100644
--- a/backend/core/models/migrationscripts/register.go
+++ b/backend/core/models/migrationscripts/register.go
@@ -111,5 +111,6 @@ func All() []plugin.MigrationScript {
                new(addSubtabknameToDeployment),
                new(addStore),
                new(addSubtaskField),
+               new(addDisplayTitleAndUrl),
        }
 }
diff --git 
a/backend/plugins/bamboo/models/migrationscripts/20240411_add_link_href_to_plan_build.go
 
b/backend/plugins/bamboo/models/migrationscripts/20240411_add_link_href_to_plan_build.go
new file mode 100644
index 000000000..cb212b8ba
--- /dev/null
+++ 
b/backend/plugins/bamboo/models/migrationscripts/20240411_add_link_href_to_plan_build.go
@@ -0,0 +1,55 @@
+/*
+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/helpers/migrationhelper"
+)
+
+type addLinkHrefToBambooPlanBuild struct{}
+
+type bambooPlanBuild20240411 struct {
+       LinkHref string
+}
+
+func (bambooPlanBuild20240411) TableName() string {
+       return "_tool_bamboo_plan_builds"
+}
+
+type BambooPlanBuildVcsRevision20240411 struct {
+       DisplayTitle string `json:"displayTitle"`
+       Url          string `json:"url"`
+}
+
+func (BambooPlanBuildVcsRevision20240411) TableName() string {
+       return "_tool_bamboo_plan_build_commits"
+}
+
+func (u *addLinkHrefToBambooPlanBuild) Up(baseRes context.BasicRes) 
errors.Error {
+       return migrationhelper.AutoMigrateTables(baseRes, 
&bambooPlanBuild20240411{}, &BambooPlanBuildVcsRevision20240411{})
+}
+
+func (*addLinkHrefToBambooPlanBuild) Version() uint64 {
+       return 20240411150361
+}
+
+func (*addLinkHrefToBambooPlanBuild) Name() string {
+       return "add display_title and url to bamboo plan build and bamboo plan 
build commit"
+}
diff --git a/backend/plugins/bamboo/models/migrationscripts/register.go 
b/backend/plugins/bamboo/models/migrationscripts/register.go
index c257892f9..d7ef35c7e 100644
--- a/backend/plugins/bamboo/models/migrationscripts/register.go
+++ b/backend/plugins/bamboo/models/migrationscripts/register.go
@@ -37,5 +37,6 @@ func All() []plugin.MigrationScript {
                new(renameMultiBambooRawTables20230920),
                new(addMissingPrimaryKeyForBambooPlanBuildVcsRevision),
                new(addQueuedFieldsInJobBuild20231128),
+               new(addLinkHrefToBambooPlanBuild),
        }
 }
diff --git a/backend/plugins/bamboo/models/plan_build.go 
b/backend/plugins/bamboo/models/plan_build.go
index 1b74e6eca..4b0351ecc 100644
--- a/backend/plugins/bamboo/models/plan_build.go
+++ b/backend/plugins/bamboo/models/plan_build.go
@@ -28,6 +28,7 @@ type BambooPlanBuild struct {
        ConnectionId             uint64 `gorm:"primaryKey"`
        PlanBuildKey             string `gorm:"primaryKey"`
        Expand                   string `json:"expand"`
+       LinkHref                 string `json:"linkHref"`
        Number                   int    `json:"number"`
        BuildNumber              int    `json:"buildNumber"`
        PlanName                 string `json:"planName"`
@@ -79,6 +80,7 @@ func (apiRes *ApiBambooPlanBuild) Convert() *BambooPlanBuild {
        return &BambooPlanBuild{
                PlanBuildKey:             apiRes.Key,
                Expand:                   apiRes.Expand,
+               LinkHref:                 apiRes.Link.Href,
                Number:                   apiRes.Number,
                BuildNumber:              apiRes.BuildNumber,
                PlanName:                 apiRes.PlanName,
@@ -115,7 +117,11 @@ func (apiRes *ApiBambooPlanBuild) Convert() 
*BambooPlanBuild {
 }
 
 type ApiBambooPlanBuild struct {
-       Expand                   string     `json:"expand"`
+       Expand string `json:"expand"`
+       Link   struct {
+               Href string `json:"href"`
+               Rel  string `json:"rel"`
+       } `json:"link"`
        PlanName                 string     `json:"planName"`
        ProjectName              string     `json:"projectName"`
        BuildResultKey           string     `json:"buildResultKey"`
diff --git a/backend/plugins/bamboo/models/plan_build_commit.go 
b/backend/plugins/bamboo/models/plan_build_commit.go
index a9998c1ab..f1c99ab5a 100644
--- a/backend/plugins/bamboo/models/plan_build_commit.go
+++ b/backend/plugins/bamboo/models/plan_build_commit.go
@@ -28,6 +28,8 @@ type BambooPlanBuildVcsRevision struct {
        RepositoryId   int
        RepositoryName string `json:"repositoryName"`
        VcsRevisionKey string `gorm:"primaryKey"`
+       DisplayTitle   string `json:"displayTitle"`
+       Url            string `json:"url"`
        common.NoPKModel
 }
 
diff --git 
a/backend/plugins/bamboo/tasks/deploy_build_to_deployment_commit_convertor.go 
b/backend/plugins/bamboo/tasks/deploy_build_to_deployment_commit_convertor.go
index ab2d8199b..e29155b50 100644
--- 
a/backend/plugins/bamboo/tasks/deploy_build_to_deployment_commit_convertor.go
+++ 
b/backend/plugins/bamboo/tasks/deploy_build_to_deployment_commit_convertor.go
@@ -19,11 +19,12 @@ package tasks
 
 import (
        "fmt"
-       "github.com/apache/incubator-devlake/core/models/common"
        "reflect"
        "strconv"
        "time"
 
+       "github.com/apache/incubator-devlake/core/models/common"
+
        "github.com/apache/incubator-devlake/core/dal"
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -136,9 +137,10 @@ func ConvertDeployBuildsToDeploymentCommits(taskCtx 
plugin.SubTaskContext) error
                                        StartedDate:  input.ExecutedDate,
                                        FinishedDate: input.FinishedDate,
                                },
-                               CommitSha: input.VcsRevisionKey,
-                               RefName:   input.PlanBranchName,
-                               RepoId:    strconv.Itoa(input.RepositoryId),
+                               CommitSha:    input.VcsRevisionKey,
+                               RefName:      input.PlanBranchName,
+                               RepoId:       strconv.Itoa(input.RepositoryId),
+                               DisplayTitle: 
input.GenerateCICDDeploymentCommitName(),
                        }
                        if 
data.RegexEnricher.ReturnNameIfMatched(devops.ENV_NAME_PATTERN, 
input.Environment) != "" {
                                deploymentCommit.Environment = devops.PRODUCTION
diff --git 
a/backend/plugins/bamboo/tasks/deploy_build_to_deployment_convertor.go 
b/backend/plugins/bamboo/tasks/deploy_build_to_deployment_convertor.go
index 0a2c014bc..badf42a53 100644
--- a/backend/plugins/bamboo/tasks/deploy_build_to_deployment_convertor.go
+++ b/backend/plugins/bamboo/tasks/deploy_build_to_deployment_convertor.go
@@ -103,6 +103,7 @@ func ConvertDeployBuildsToDeployments(taskCtx 
plugin.SubTaskContext) errors.Erro
                                        StartedDate:  input.ExecutedDate,
                                        FinishedDate: input.FinishedDate,
                                },
+                               DisplayTitle: name,
                        }
                        if 
data.RegexEnricher.ReturnNameIfMatched(devops.ENV_NAME_PATTERN, 
input.Environment) != "" {
                                deployment.Environment = devops.PRODUCTION
diff --git a/backend/plugins/bamboo/tasks/plan_build_convertor.go 
b/backend/plugins/bamboo/tasks/plan_build_convertor.go
index 14d27ac20..c86e8ae53 100644
--- a/backend/plugins/bamboo/tasks/plan_build_convertor.go
+++ b/backend/plugins/bamboo/tasks/plan_build_convertor.go
@@ -18,6 +18,9 @@ limitations under the License.
 package tasks
 
 import (
+       "reflect"
+       "time"
+
        "github.com/apache/incubator-devlake/core/dal"
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -26,8 +29,6 @@ import (
        "github.com/apache/incubator-devlake/core/plugin"
        "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/plugins/bamboo/models"
-       "reflect"
-       "time"
 )
 
 var ConvertPlanBuildsMeta = plugin.SubTaskMeta{
@@ -40,6 +41,7 @@ var ConvertPlanBuildsMeta = plugin.SubTaskMeta{
 
 func ConvertPlanBuilds(taskCtx plugin.SubTaskContext) errors.Error {
        db := taskCtx.GetDal()
+       logger := taskCtx.GetLogger()
        rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, 
RAW_PLAN_BUILD_TABLE)
        cursor, err := db.Cursor(
                dal.From(&models.BambooPlanBuild{}),
@@ -87,6 +89,13 @@ func ConvertPlanBuilds(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        Default:    devops.STATUS_OTHER,
                                }, line.LifeCycleState),
                                OriginalStatus: line.LifeCycleState,
+                               DisplayTitle:   line.GenerateCICDPipeLineName(),
+                       }
+                       homepage, err := getBambooHomePage(line.LinkHref)
+                       if err != nil {
+                               logger.Warn(err, "get bamboo home")
+                       } else {
+                               domainPlanBuild.Url = homepage + "/browse/" + 
line.PlanKey
                        }
 
                        domainPlanBuild.Type = line.Type
diff --git a/backend/plugins/bamboo/tasks/plan_build_extractor.go 
b/backend/plugins/bamboo/tasks/plan_build_extractor.go
index 273e61764..7f5c6eb5b 100644
--- a/backend/plugins/bamboo/tasks/plan_build_extractor.go
+++ b/backend/plugins/bamboo/tasks/plan_build_extractor.go
@@ -31,6 +31,7 @@ var _ plugin.SubTaskEntryPoint = ExtractPlanBuild
 
 func ExtractPlanBuild(taskCtx plugin.SubTaskContext) errors.Error {
        rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, 
RAW_PLAN_BUILD_TABLE)
+       logger := taskCtx.GetLogger()
 
        extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
                RawDataSubTaskArgs: *rawDataSubTaskArgs,
@@ -47,6 +48,13 @@ func ExtractPlanBuild(taskCtx plugin.SubTaskContext) 
errors.Error {
                        body.Type = 
data.RegexEnricher.ReturnNameIfMatched(devops.DEPLOYMENT, body.PlanName)
                        body.Environment = 
data.RegexEnricher.ReturnNameIfMatched(devops.PRODUCTION, body.PlanName)
 
+                       var url string
+                       homepage, errGetHomePage := 
getBambooHomePage(body.LinkHref)
+                       if errGetHomePage != nil {
+                               logger.Warn(errGetHomePage, "get bamboo home")
+                       } else {
+                               url = homepage + "/browse/" + body.PlanKey
+                       }
                        results := make([]interface{}, 0)
                        results = append(results, body)
                        // As job build can get more accuracy repo info,
@@ -59,6 +67,8 @@ func ExtractPlanBuild(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        RepositoryId:   v.RepositoryId,
                                        RepositoryName: v.RepositoryName,
                                        VcsRevisionKey: v.VcsRevisionKey,
+                                       DisplayTitle:   
body.GenerateCICDPipeLineName(),
+                                       Url:            url,
                                })
                        }
 
diff --git a/backend/plugins/bamboo/tasks/plan_commit_convertor.go 
b/backend/plugins/bamboo/tasks/plan_commit_convertor.go
index ec9384b49..13104d89c 100644
--- a/backend/plugins/bamboo/tasks/plan_commit_convertor.go
+++ b/backend/plugins/bamboo/tasks/plan_commit_convertor.go
@@ -60,8 +60,10 @@ func ConvertPlanVcs(taskCtx plugin.SubTaskContext) 
errors.Error {
                Convert: func(inputRow interface{}) ([]interface{}, 
errors.Error) {
                        line := inputRow.(*models.BambooPlanBuildVcsRevision)
                        domainPlanVcs := &devops.CiCDPipelineCommit{
-                               PipelineId: 
planBuildIdGen.Generate(data.Options.ConnectionId, line.PlanBuildKey),
-                               CommitSha:  line.VcsRevisionKey,
+                               PipelineId:   
planBuildIdGen.Generate(data.Options.ConnectionId, line.PlanBuildKey),
+                               CommitSha:    line.VcsRevisionKey,
+                               DisplayTitle: line.DisplayTitle,
+                               Url:          line.Url,
                        }
                        domainPlanVcs.RepoId = repoMap[line.RepositoryId]
                        fakeRepoUrl, err := 
generateFakeRepoUrl(data.ApiClient.GetEndpoint(), line.RepositoryId)
diff --git a/backend/plugins/bitbucket/tasks/deployment_convertor.go 
b/backend/plugins/bitbucket/tasks/deployment_convertor.go
index ca6ea9a4a..8b2fbbcc3 100644
--- a/backend/plugins/bitbucket/tasks/deployment_convertor.go
+++ b/backend/plugins/bitbucket/tasks/deployment_convertor.go
@@ -111,11 +111,13 @@ func ConvertDeployments(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        StartedDate:  
bitbucketDeployment.StartedOn,
                                        FinishedDate: 
bitbucketDeployment.CompletedOn,
                                },
-                               DurationSec: duration,
-                               CommitSha:   bitbucketDeployment.CommitSha,
-                               RefName:     bitbucketDeployment.RefName,
-                               RepoId:      repoId,
-                               RepoUrl:     repo.HTMLUrl,
+                               DurationSec:  duration,
+                               CommitSha:    bitbucketDeployment.CommitSha,
+                               RefName:      bitbucketDeployment.RefName,
+                               RepoId:       repoId,
+                               RepoUrl:      repo.HTMLUrl,
+                               DisplayTitle: bitbucketDeployment.Name,
+                               Url:          bitbucketDeployment.WebUrl,
                        }
                        if domainDeployCommit.Environment == devops.TEST {
                                // Theoretically, environment cannot be "Test" 
according to
diff --git a/backend/plugins/bitbucket/tasks/pipeline_convertor.go 
b/backend/plugins/bitbucket/tasks/pipeline_convertor.go
index 9a8d80bdf..580dd5b90 100644
--- a/backend/plugins/bitbucket/tasks/pipeline_convertor.go
+++ b/backend/plugins/bitbucket/tasks/pipeline_convertor.go
@@ -76,11 +76,13 @@ func ConvertPipelines(taskCtx plugin.SubTaskContext) 
errors.Error {
                        domainEntityId := 
pipelineIdGen.Generate(data.Options.ConnectionId, bitbucketPipeline.BitbucketId)
                        results := make([]interface{}, 0, 2)
                        domainPipelineCommit := &devops.CiCDPipelineCommit{
-                               PipelineId: domainEntityId,
-                               RepoId:     repoId,
-                               CommitSha:  bitbucketPipeline.CommitSha,
-                               Branch:     bitbucketPipeline.RefName,
-                               RepoUrl:    repo.HTMLUrl,
+                               PipelineId:   domainEntityId,
+                               RepoId:       repoId,
+                               CommitSha:    bitbucketPipeline.CommitSha,
+                               Branch:       bitbucketPipeline.RefName,
+                               RepoUrl:      repo.HTMLUrl,
+                               DisplayTitle: fmt.Sprintf("%s/%d", 
domainEntityId, bitbucketPipeline.BuildNumber),
+                               Url:          bitbucketPipeline.WebUrl,
                        }
                        domainPipeline := &devops.CICDPipeline{
                                DomainEntity: domainlayer.DomainEntity{
@@ -106,8 +108,10 @@ func ConvertPipelines(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        StartedDate:  
bitbucketPipeline.BitbucketCreatedOn,
                                        FinishedDate: 
bitbucketPipeline.BitbucketCompleteOn,
                                },
-                               DurationSec: 
float64(bitbucketPipeline.DurationInSeconds),
-                               CicdScopeId: repoId,
+                               DurationSec:  
float64(bitbucketPipeline.DurationInSeconds),
+                               CicdScopeId:  repoId,
+                               DisplayTitle: fmt.Sprintf("%s/%d", 
domainEntityId, bitbucketPipeline.BuildNumber),
+                               Url:          bitbucketPipeline.WebUrl,
                        }
                        results = append(results, domainPipelineCommit, 
domainPipeline)
                        return results, nil
diff --git a/backend/plugins/bitbucket/tasks/pipeline_extractor.go 
b/backend/plugins/bitbucket/tasks/pipeline_extractor.go
index dd7e68880..ec924db8d 100644
--- a/backend/plugins/bitbucket/tasks/pipeline_extractor.go
+++ b/backend/plugins/bitbucket/tasks/pipeline_extractor.go
@@ -106,9 +106,6 @@ func ExtractApiPipelines(taskCtx plugin.SubTaskContext) 
errors.Error {
                                Type:                
data.RegexEnricher.ReturnNameIfMatched(devops.DEPLOYMENT, 
bitbucketApiPipeline.Target.RefName),
                                Environment:         
data.RegexEnricher.ReturnNameIfOmittedOrMatched(devops.PRODUCTION, 
bitbucketApiPipeline.Target.RefName),
                        }
-                       if err != nil {
-                               return nil, err
-                       }
                        if bitbucketApiPipeline.State.Result != nil {
                                bitbucketPipeline.Result = 
bitbucketApiPipeline.State.Result.Name
                        } else if bitbucketApiPipeline.State.Stage != nil {
diff --git a/backend/plugins/circleci/tasks/workflow_converter.go 
b/backend/plugins/circleci/tasks/workflow_converter.go
index 9e923c9d3..91806fad5 100644
--- a/backend/plugins/circleci/tasks/workflow_converter.go
+++ b/backend/plugins/circleci/tasks/workflow_converter.go
@@ -18,6 +18,7 @@ limitations under the License.
 package tasks
 
 import (
+       "fmt"
        "reflect"
 
        "github.com/apache/incubator-devlake/core/dal"
@@ -80,8 +81,9 @@ func ConvertWorkflows(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        Failure: []string{"failed", "failing", 
"error"}, // not_run,canceled
                                        Default: devops.RESULT_DEFAULT,
                                }, userTool.Status),
-                               Type:        
data.RegexEnricher.ReturnNameIfMatched(devops.DEPLOYMENT, userTool.Name),
-                               Environment: 
data.RegexEnricher.ReturnNameIfOmittedOrMatched(devops.PRODUCTION, 
userTool.Name),
+                               Type:         
data.RegexEnricher.ReturnNameIfMatched(devops.DEPLOYMENT, userTool.Name),
+                               Environment:  
data.RegexEnricher.ReturnNameIfOmittedOrMatched(devops.PRODUCTION, 
userTool.Name),
+                               DisplayTitle: fmt.Sprintf("%s#%d", 
userTool.Name, userTool.PipelineNumber),
                        }
                        result := make([]interface{}, 0, 2)
                        result = append(result, pipeline)
@@ -91,11 +93,12 @@ func ConvertWorkflows(taskCtx plugin.SubTaskContext) 
errors.Error {
                        if p, err := findPipelineById(db, userTool.PipelineId); 
err == nil {
                                if p.Vcs.Revision != "" {
                                        result = append(result, 
&devops.CiCDPipelineCommit{
-                                               PipelineId: pipeline.Id,
-                                               CommitSha:  p.Vcs.Revision,
-                                               Branch:     p.Vcs.Branch,
-                                               RepoId:     
p.Vcs.OriginRepositoryUrl,
-                                               RepoUrl:    
p.Vcs.OriginRepositoryUrl,
+                                               PipelineId:   pipeline.Id,
+                                               CommitSha:    p.Vcs.Revision,
+                                               Branch:       p.Vcs.Branch,
+                                               RepoId:       
p.Vcs.OriginRepositoryUrl,
+                                               RepoUrl:      
p.Vcs.OriginRepositoryUrl,
+                                               DisplayTitle: 
pipeline.DisplayTitle,
                                        })
                                }
                        }
diff --git a/backend/plugins/dora/tasks/deployment_commits_generator.go 
b/backend/plugins/dora/tasks/deployment_commits_generator.go
index e29846997..826e17728 100644
--- a/backend/plugins/dora/tasks/deployment_commits_generator.go
+++ b/backend/plugins/dora/tasks/deployment_commits_generator.go
@@ -158,6 +158,8 @@ func GenerateDeploymentCommits(taskCtx 
plugin.SubTaskContext) errors.Error {
                                CicdScopeId:      pipelineCommit.CicdScopeId,
                                CicdDeploymentId: pipelineCommit.PipelineId,
                                Name:             pipelineCommit.PipelineName,
+                               DisplayTitle:     pipelineCommit.DisplayTitle,
+                               Url:              pipelineCommit.Url,
                                Result:           pipelineCommit.Result,
                                OriginalStatus:   pipelineCommit.OriginalStatus,
                                OriginalResult:   pipelineCommit.OriginalResult,
diff --git a/backend/plugins/dora/tasks/deployment_generator.go 
b/backend/plugins/dora/tasks/deployment_generator.go
index 08102fb42..0defd4205 100644
--- a/backend/plugins/dora/tasks/deployment_generator.go
+++ b/backend/plugins/dora/tasks/deployment_generator.go
@@ -132,6 +132,8 @@ func GenerateDeployment(taskCtx plugin.SubTaskContext) 
errors.Error {
                                },
                                CicdScopeId:    pipelineExInfo.CicdScopeId,
                                Name:           pipelineExInfo.Name,
+                               DisplayTitle:   pipelineExInfo.DisplayTitle,
+                               Url:            pipelineExInfo.Url,
                                Result:         pipelineExInfo.Result,
                                Status:         pipelineExInfo.Status,
                                OriginalStatus: pipelineExInfo.OriginalStatus,
diff --git a/backend/plugins/github/models/deployment.go 
b/backend/plugins/github/models/deployment.go
index f6d87684a..6a818be45 100644
--- a/backend/plugins/github/models/deployment.go
+++ b/backend/plugins/github/models/deployment.go
@@ -25,9 +25,11 @@ import (
 
 type GithubDeployment struct {
        common.NoPKModel  `json:"-" mapstructure:"-"`
-       ConnectionId      uint64     `json:"connection_id" gorm:"primaryKey"`
-       GithubId          int        `json:"github_id"`
-       Id                string     `json:"id" 
gorm:"type:varchar(255);primaryKey"`
+       ConnectionId      uint64 `json:"connection_id" gorm:"primaryKey"`
+       GithubId          int    `json:"github_id"`
+       Id                string `json:"id" gorm:"type:varchar(255);primaryKey"`
+       DisplayTitle      string
+       Url               string
        DatabaseId        uint       `json:"database_id"`
        CommitOid         string     `json:"commit_oid" 
gorm:"type:varchar(255)"`
        Description       string     `json:"description" 
gorm:"type:varchar(255)"`
diff --git 
a/backend/plugins/github/models/migrationscripts/20240410_add_workflow_display_title.go
 
b/backend/plugins/github/models/migrationscripts/20240410_add_workflow_display_title.go
new file mode 100644
index 000000000..4cd789f4e
--- /dev/null
+++ 
b/backend/plugins/github/models/migrationscripts/20240410_add_workflow_display_title.go
@@ -0,0 +1,55 @@
+/*
+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/helpers/migrationhelper"
+)
+
+type addWorkflowDisplayTitle struct{}
+
+type run20240410 struct {
+       DisplayTitle string
+}
+
+func (run20240410) TableName() string {
+       return "_tool_github_runs"
+}
+
+type deployment20240410 struct {
+       DisplayTitle string
+       Url          string
+}
+
+func (deployment20240410) TableName() string {
+       return "_tool_github_deployments"
+}
+
+func (u *addWorkflowDisplayTitle) Up(baseRes context.BasicRes) errors.Error {
+       return migrationhelper.AutoMigrateTables(baseRes, &run20240410{}, 
&deployment20240410{})
+}
+
+func (*addWorkflowDisplayTitle) Version() uint64 {
+       return 20240410150358
+}
+
+func (*addWorkflowDisplayTitle) Name() string {
+       return "add display title and url to github runs and deployments"
+}
diff --git a/backend/plugins/github/models/migrationscripts/register.go 
b/backend/plugins/github/models/migrationscripts/register.go
index a179a1bfd..1f09898df 100644
--- a/backend/plugins/github/models/migrationscripts/register.go
+++ b/backend/plugins/github/models/migrationscripts/register.go
@@ -47,5 +47,6 @@ func All() []plugin.MigrationScript {
                new(modifyGithubMilestone),
                new(addEnvNamePattern),
                new(modifyIssueTypeLength),
+               new(addWorkflowDisplayTitle),
        }
 }
diff --git a/backend/plugins/github/models/run.go 
b/backend/plugins/github/models/run.go
index 7bf55e59e..34d211647 100644
--- a/backend/plugins/github/models/run.go
+++ b/backend/plugins/github/models/run.go
@@ -18,8 +18,9 @@ limitations under the License.
 package models
 
 import (
-       "github.com/apache/incubator-devlake/core/models/common"
        "time"
+
+       "github.com/apache/incubator-devlake/core/models/common"
 )
 
 type GithubRun struct {
@@ -39,6 +40,7 @@ type GithubRun struct {
        WorkflowID       int        `json:"workflow_id"`
        CheckSuiteID     int64      `json:"check_suite_id"`
        CheckSuiteNodeID string     `json:"check_suite_node_id" 
gorm:"type:varchar(255)"`
+       DisplayTitle     string     `json:"display_title" gorm:"type:text"`
        URL              string     `json:"url" gorm:"type:varchar(255)"`
        HTMLURL          string     `json:"html_url" gorm:"type:varchar(255)"`
        GithubCreatedAt  *time.Time `json:"created_at"`
diff --git a/backend/plugins/github/tasks/cicd_run_convertor.go 
b/backend/plugins/github/tasks/cicd_run_convertor.go
index 505d85fce..d4917862d 100644
--- a/backend/plugins/github/tasks/cicd_run_convertor.go
+++ b/backend/plugins/github/tasks/cicd_run_convertor.go
@@ -117,6 +117,8 @@ func ConvertRuns(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        Default:    devops.STATUS_OTHER,
                                }, line.Status),
                                OriginalStatus: line.Status,
+                               DisplayTitle:   line.DisplayTitle,
+                               Url:            line.URL,
                        }
                        if line.GithubUpdatedAt != nil && line.RunStartedAt != 
nil {
                                domainPipeline.DurationSec = 
float64(line.GithubUpdatedAt.Sub(*line.RunStartedAt).Milliseconds() / 1e3)
@@ -125,10 +127,12 @@ func ConvertRuns(taskCtx plugin.SubTaskContext) 
errors.Error {
                        domainPipelineCommit := &devops.CiCDPipelineCommit{
                                PipelineId: runIdGen.Generate(
                                        data.Options.ConnectionId, line.RepoId, 
line.ID),
-                               CommitSha: line.HeadSha,
-                               Branch:    line.HeadBranch,
-                               RepoId:    
repoIdGen.Generate(data.Options.ConnectionId, repoId),
-                               RepoUrl:   repo.HTMLUrl,
+                               CommitSha:    line.HeadSha,
+                               Branch:       line.HeadBranch,
+                               RepoId:       
repoIdGen.Generate(data.Options.ConnectionId, repoId),
+                               RepoUrl:      repo.HTMLUrl,
+                               DisplayTitle: line.DisplayTitle,
+                               Url:          line.URL,
                        }
 
                        return []interface{}{
diff --git a/backend/plugins/github/tasks/deployment_convertor.go 
b/backend/plugins/github/tasks/deployment_convertor.go
index 0d9f89dc6..47cdd2319 100644
--- a/backend/plugins/github/tasks/deployment_convertor.go
+++ b/backend/plugins/github/tasks/deployment_convertor.go
@@ -95,10 +95,12 @@ func ConvertDeployment(taskCtx plugin.SubTaskContext) 
errors.Error {
                                        StartedDate:  
&githubDeployment.CreatedDate,
                                        FinishedDate: 
&githubDeployment.UpdatedDate,
                                },
-                               CommitSha: githubDeployment.CommitOid,
-                               RefName:   githubDeployment.RefName,
-                               RepoId:    
deploymentScopeIdGen.Generate(githubDeployment.ConnectionId, 
githubDeployment.GithubId),
-                               RepoUrl:   githubDeployment.RepositoryUrl,
+                               CommitSha:    githubDeployment.CommitOid,
+                               RefName:      githubDeployment.RefName,
+                               RepoId:       
deploymentScopeIdGen.Generate(githubDeployment.ConnectionId, 
githubDeployment.GithubId),
+                               RepoUrl:      githubDeployment.RepositoryUrl,
+                               DisplayTitle: githubDeployment.DisplayTitle,
+                               Url:          githubDeployment.Url,
                        }
 
                        durationSec := 
float64(githubDeployment.UpdatedDate.Sub(githubDeployment.CreatedDate).Milliseconds()
 / 1e3)
diff --git a/backend/plugins/github_graphql/tasks/deployment_collector.go 
b/backend/plugins/github_graphql/tasks/deployment_collector.go
index 437088629..b81e3d107 100644
--- a/backend/plugins/github_graphql/tasks/deployment_collector.go
+++ b/backend/plugins/github_graphql/tasks/deployment_collector.go
@@ -81,6 +81,20 @@ type GraphqlQueryDeploymentDeployment struct {
        } `graphql:"repository"`
        CreatedAt time.Time
        UpdatedAt time.Time
+       Commit    struct {
+               Oid     string `graphql:"oid"`
+               Message string `graphql:"message"`
+               Author  struct {
+                       Name  string `graphql:"name"`
+                       Email string `graphql:"email"`
+               } `graphql:"author"`
+               CommittedDate time.Time `graphql:"committedDate"`
+       } `graphql:"commit"`
+       // Commits struct {
+       //      PageInfo   *api.GraphqlQueryPageInfo
+       //      Nodes      []GraphqlQueryCommit `graphql:"nodes"`
+       //      TotalCount graphql.Int
+       // } `graphql:"commits(first: 100)"`
 }
 
 // CollectDeployments will request github api via graphql and store the result 
into raw layer.
diff --git a/backend/plugins/github_graphql/tasks/deployment_extractor.go 
b/backend/plugins/github_graphql/tasks/deployment_extractor.go
index b2150effd..1eb6c252b 100644
--- a/backend/plugins/github_graphql/tasks/deployment_extractor.go
+++ b/backend/plugins/github_graphql/tasks/deployment_extractor.go
@@ -19,6 +19,7 @@ package tasks
 
 import (
        "encoding/json"
+       "strings"
 
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/models/common"
@@ -81,6 +82,8 @@ func convertGithubDeployment(deployment 
GraphqlQueryDeploymentDeployment, connec
                GithubId:          githubId,
                NoPKModel:         common.NewNoPKModel(),
                Id:                deployment.Id,
+               DisplayTitle:      strings.Split(deployment.Commit.Message, 
"\n")[0],
+               Url:               deployment.Repository.Url + "/deployments/" 
+ deployment.Environment,
                DatabaseId:        deployment.DatabaseId,
                Payload:           deployment.Payload,
                Description:       deployment.Description,
diff --git a/backend/plugins/bamboo/models/migrationscripts/register.go 
b/backend/plugins/gitlab/models/migrationscripts/20240411_add_web_url_to_pipeline.go
similarity index 50%
copy from backend/plugins/bamboo/models/migrationscripts/register.go
copy to 
backend/plugins/gitlab/models/migrationscripts/20240411_add_web_url_to_pipeline.go
index c257892f9..afd1434f6 100644
--- a/backend/plugins/bamboo/models/migrationscripts/register.go
+++ 
b/backend/plugins/gitlab/models/migrationscripts/20240411_add_web_url_to_pipeline.go
@@ -18,24 +18,29 @@ limitations under the License.
 package migrationscripts
 
 import (
-       "github.com/apache/incubator-devlake/core/plugin"
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/helpers/migrationhelper"
 )
 
-// All return all the migration scripts
-func All() []plugin.MigrationScript {
-       return []plugin.MigrationScript{
-               new(addInitTables),
-               new(addConnectionIdToTransformationRule),
-               new(addTypeAndEnvironment),
-               new(renameTr2ScopeConfig),
-               new(addRawParamTableForScope),
-               new(addScopeConfigId),
-               new(addEnvNamePattern),
-               new(addPlanResultKey),
-               new(renameToolBambooDeployBuild20230919),
-               new(renameToolBambooDeployEnvironments20230919),
-               new(renameMultiBambooRawTables20230920),
-               new(addMissingPrimaryKeyForBambooPlanBuildVcsRevision),
-               new(addQueuedFieldsInJobBuild20231128),
-       }
+type addWebUrlToGitlabPipelineProject struct{}
+
+type gitlabPipelineProject20240411 struct {
+       WebUrl string `gorm:"type:varchar(255)"`
+}
+
+func (gitlabPipelineProject20240411) TableName() string {
+       return "_tool_gitlab_pipeline_projects"
+}
+
+func (u *addWebUrlToGitlabPipelineProject) Up(baseRes context.BasicRes) 
errors.Error {
+       return migrationhelper.AutoMigrateTables(baseRes, 
&gitlabPipelineProject20240411{})
+}
+
+func (*addWebUrlToGitlabPipelineProject) Version() uint64 {
+       return 20240411150359
+}
+
+func (*addWebUrlToGitlabPipelineProject) Name() string {
+       return "add web url to gitlab pipeline projects"
 }
diff --git a/backend/plugins/gitlab/models/migrationscripts/register.go 
b/backend/plugins/gitlab/models/migrationscripts/register.go
index c6d97dd20..270bb296f 100644
--- a/backend/plugins/gitlab/models/migrationscripts/register.go
+++ b/backend/plugins/gitlab/models/migrationscripts/register.go
@@ -47,5 +47,6 @@ func All() []plugin.MigrationScript {
                new(modifyDeploymentMessageType),
                new(addTimeToGitlabPipelineProject),
                new(modifyDeploymentCommitTitle),
+               new(addWebUrlToGitlabPipelineProject),
        }
 }
diff --git a/backend/plugins/gitlab/models/pipeline.go 
b/backend/plugins/gitlab/models/pipeline.go
index a11e00024..00dce35f6 100644
--- a/backend/plugins/gitlab/models/pipeline.go
+++ b/backend/plugins/gitlab/models/pipeline.go
@@ -58,6 +58,7 @@ type GitlabPipelineProject struct {
        PipelineId      int    `gorm:"primaryKey"`
        ProjectId       int    `gorm:"primaryKey"`
        Ref             string `gorm:"type:varchar(255)"`
+       WebUrl          string `gorm:"type:varchar(255)"`
        Sha             string `gorm:"type:varchar(255)"`
        GitlabCreatedAt *time.Time
        GitlabUpdatedAt *time.Time
diff --git a/backend/plugins/gitlab/tasks/deployment_convertor.go 
b/backend/plugins/gitlab/tasks/deployment_convertor.go
index 4db399b95..d7ff0d774 100644
--- a/backend/plugins/gitlab/tasks/deployment_convertor.go
+++ b/backend/plugins/gitlab/tasks/deployment_convertor.go
@@ -125,6 +125,8 @@ func ConvertDeployment(taskCtx plugin.SubTaskContext) 
errors.Error {
                                RefName:           gitlabDeployment.Ref,
                                RepoId:            
projectIdGen.Generate(data.Options.ConnectionId, data.Options.ProjectId),
                                RepoUrl:           repo.WebUrl,
+                               DisplayTitle:      
gitlabDeployment.DeployableCommitTitle,
+                               Url:               repo.WebUrl + 
"/environments",
                        }
                        if data.RegexEnricher != nil {
                                if 
data.RegexEnricher.ReturnNameIfMatched(devops.ENV_NAME_PATTERN, 
gitlabDeployment.Environment) != "" {
diff --git a/backend/plugins/gitlab/tasks/pipeline_commit_convertor.go 
b/backend/plugins/gitlab/tasks/pipeline_commit_convertor.go
index a15928c4d..4984270d9 100644
--- a/backend/plugins/gitlab/tasks/pipeline_commit_convertor.go
+++ b/backend/plugins/gitlab/tasks/pipeline_commit_convertor.go
@@ -82,6 +82,8 @@ func ConvertPipelineCommits(taskCtx plugin.SubTaskContext) 
errors.Error {
                                RepoId: 
didgen.NewDomainIdGenerator(&models.GitlabProject{}).
                                        
Generate(gitlabPipelineCommit.ConnectionId, gitlabPipelineCommit.ProjectId),
                                RepoUrl: repo.WebUrl,
+                               // DisplayTitle: gitlabPipelineCommit.Ref,
+                               Url: gitlabPipelineCommit.WebUrl,
                        }
 
                        return []interface{}{
diff --git a/backend/plugins/gitlab/tasks/pipeline_detail_convertor.go 
b/backend/plugins/gitlab/tasks/pipeline_detail_convertor.go
index 3818a9a69..1b652274f 100644
--- a/backend/plugins/gitlab/tasks/pipeline_detail_convertor.go
+++ b/backend/plugins/gitlab/tasks/pipeline_detail_convertor.go
@@ -103,6 +103,8 @@ func ConvertDetailPipelines(taskCtx plugin.SubTaskContext) 
errors.Error {
                                Environment:       gitlabPipeline.Environment,
                                Type:              gitlabPipeline.Type,
                                DurationSec:       
float64(gitlabPipeline.Duration),
+                               // DisplayTitle:      gitlabPipeline.Ref,
+                               Url: gitlabPipeline.WebUrl,
                        }
                        return []interface{}{
                                domainPipeline,
diff --git a/backend/plugins/gitlab/tasks/pipeline_detail_extractor.go 
b/backend/plugins/gitlab/tasks/pipeline_detail_extractor.go
index 83dab29c7..a5e597e23 100644
--- a/backend/plugins/gitlab/tasks/pipeline_detail_extractor.go
+++ b/backend/plugins/gitlab/tasks/pipeline_detail_extractor.go
@@ -71,9 +71,6 @@ func ExtractApiPipelineDetails(taskCtx plugin.SubTaskContext) 
errors.Error {
                                Type:            
data.RegexEnricher.ReturnNameIfMatched(devops.DEPLOYMENT, 
gitlabApiPipeline.Ref),
                                Environment:     
data.RegexEnricher.ReturnNameIfMatched(devops.PRODUCTION, 
gitlabApiPipeline.Ref),
                        }
-                       if err != nil {
-                               return nil, err
-                       }
 
                        results := make([]interface{}, 0, 1)
                        results = append(results, gitlabPipeline)
diff --git a/backend/plugins/gitlab/tasks/pipeline_extractor.go 
b/backend/plugins/gitlab/tasks/pipeline_extractor.go
index 738109ac4..9cce27c80 100644
--- a/backend/plugins/gitlab/tasks/pipeline_extractor.go
+++ b/backend/plugins/gitlab/tasks/pipeline_extractor.go
@@ -87,6 +87,7 @@ func ExtractApiPipelines(taskCtx plugin.SubTaskContext) 
errors.Error {
                                PipelineId:      gitlabApiPipeline.Id,
                                ProjectId:       data.Options.ProjectId,
                                Ref:             gitlabApiPipeline.Ref,
+                               WebUrl:          gitlabApiPipeline.WebUrl,
                                Sha:             gitlabApiPipeline.Sha,
                                GitlabCreatedAt: 
common.Iso8601TimeToTime(gitlabApiPipeline.CreatedAt),
                                GitlabUpdatedAt: 
common.Iso8601TimeToTime(gitlabApiPipeline.UpdatedAt),
diff --git a/backend/python/plugins/azuredevops/azuredevops/migrations.py 
b/backend/python/plugins/azuredevops/azuredevops/migrations.py
index b6924e037..47e2e81c9 100644
--- a/backend/python/plugins/azuredevops/azuredevops/migrations.py
+++ b/backend/python/plugins/azuredevops/azuredevops/migrations.py
@@ -199,3 +199,9 @@ def 
add_updated_date_field_in_tool_azuredevops_gitrepositories(b: MigrationScrip
     table = "_tool_azuredevops_gitrepositories"
     b.execute(f'ALTER TABLE {table} add COLUMN updated_date datetime(3) 
DEFAULT NULL', Dialect.MYSQL)
     b.execute(f'ALTER TABLE {table} add COLUMN updated_date TIMESTAMPTZ 
DEFAULT NULL', Dialect.POSTGRESQL)
+
+@migration(20240415163000, name="add queue_time field in 
_tool_azuredevops_builds")
+def add_queue_time_field_in_tool_azuredevops_builds(b: MigrationScriptBuilder):
+    table = '_tool_azuredevops_builds'
+    b.add_column(table, 'display_title', 'LONGTEXT')
+    b.add_column(table, 'url', 'LONGTEXT')
\ No newline at end of file
diff --git a/backend/python/plugins/azuredevops/azuredevops/models.py 
b/backend/python/plugins/azuredevops/azuredevops/models.py
index 8863f1b9f..28f7692d8 100644
--- a/backend/python/plugins/azuredevops/azuredevops/models.py
+++ b/backend/python/plugins/azuredevops/azuredevops/models.py
@@ -115,6 +115,8 @@ class Build(ToolModel, table=True):
     result: Optional[BuildResult]
     source_branch: str
     source_version: str
+    display_title: str = Field(source='/triggerInfo/ci.message')
+    url: str = Field(source='/_links/web/href')
 
 
 class Job(ToolModel, table=True):
diff --git a/backend/python/plugins/azuredevops/azuredevops/streams/builds.py 
b/backend/python/plugins/azuredevops/azuredevops/streams/builds.py
index af2fdf252..bbf9e7420 100644
--- a/backend/python/plugins/azuredevops/azuredevops/streams/builds.py
+++ b/backend/python/plugins/azuredevops/azuredevops/streams/builds.py
@@ -96,6 +96,8 @@ class Builds(Stream):
             environment=environment,
             type=type,
             cicd_scope_id=ctx.scope.domain_id(),
+            display_title=b.display_title,
+            url=b.url,
         )
 
         if b.source_version is not None:
@@ -105,4 +107,6 @@ class Builds(Stream):
                 branch=b.source_branch,
                 repo_id=ctx.scope.domain_id(),
                 repo_url=ctx.scope.url,
+                display_title=b.display_title,
+                url=b.url,
             )
diff --git a/backend/python/pydevlake/pydevlake/domain_layer/devops.py 
b/backend/python/pydevlake/pydevlake/domain_layer/devops.py
index 3b6608fb3..c8ef108d4 100644
--- a/backend/python/pydevlake/pydevlake/domain_layer/devops.py
+++ b/backend/python/pydevlake/pydevlake/domain_layer/devops.py
@@ -69,6 +69,9 @@ class CICDPipeline(DomainModel, table=True):
     type: Optional[CICDType]
     environment: Optional[CICDEnvironment]
 
+    display_title: Optional[str]
+    url: Optional[str]
+
 
 class CiCDPipelineCommit(NoPKModel, table=True):
     __tablename__ = 'cicd_pipeline_commits'
@@ -77,6 +80,8 @@ class CiCDPipelineCommit(NoPKModel, table=True):
     branch: str
     repo_id: str
     repo_url: str
+    display_title: Optional[str]
+    url: Optional[str]
 
 
 class CicdScope(DomainScope):


Reply via email to