You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by zh...@apache.org on 2022/10/14 03:22:44 UTC

[incubator-devlake] branch main updated: feat: add Bitbucket Deployment Collector&Extractor&Convertor (#3432)

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

zhangliang2022 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 7d974e0d feat: add Bitbucket Deployment Collector&Extractor&Convertor (#3432)
7d974e0d is described below

commit 7d974e0d19b7936b46bd1c9aa720f8f3190750bd
Author: tsoc <47...@users.noreply.github.com>
AuthorDate: Fri Oct 14 11:22:40 2022 +0800

    feat: add Bitbucket Deployment Collector&Extractor&Convertor (#3432)
    
    * feat: add bitbucket deployment collector&extractor&convertor
    
    * refactor: set some constants for bitbucket cicd
    
    * fix: fix unused ignoreHTTPStatus403
---
 plugins/bitbucket/impl/impl.go                     |   3 +
 .../models/{pipeline.go => deployment.go}          |  32 ++---
 ...gister.go => 20221013_add_deployment_tables.go} |  25 +++-
 .../models/migrationscripts/archived/deployment.go |  46 +++++++
 .../bitbucket/models/migrationscripts/register.go  |   1 +
 plugins/bitbucket/models/pipeline.go               |  15 +++
 plugins/bitbucket/tasks/api_common.go              |   7 --
 ...peline_collector.go => deployment_collector.go} |  17 ++-
 ...peline_convertor.go => deployment_convertor.go} |  64 +++++-----
 plugins/bitbucket/tasks/deployment_extractor.go    | 132 +++++++++++++++++++++
 plugins/bitbucket/tasks/pipeline_collector.go      |   1 -
 plugins/bitbucket/tasks/pipeline_convertor.go      |  10 +-
 12 files changed, 283 insertions(+), 70 deletions(-)

diff --git a/plugins/bitbucket/impl/impl.go b/plugins/bitbucket/impl/impl.go
index 5f311f48..8619687a 100644
--- a/plugins/bitbucket/impl/impl.go
+++ b/plugins/bitbucket/impl/impl.go
@@ -62,6 +62,8 @@ func (plugin Bitbucket) SubTaskMetas() []core.SubTaskMeta {
 		tasks.ExtractApiIssueCommentsMeta,
 		tasks.CollectApiPipelinesMeta,
 		tasks.ExtractApiPipelinesMeta,
+		tasks.CollectApiDeploymentsMeta,
+		tasks.ExtractApiDeploymentsMeta,
 		tasks.ConvertRepoMeta,
 		tasks.ConvertAccountsMeta,
 		tasks.ConvertPullRequestsMeta,
@@ -69,6 +71,7 @@ func (plugin Bitbucket) SubTaskMetas() []core.SubTaskMeta {
 		tasks.ConvertIssuesMeta,
 		tasks.ConvertIssueCommentsMeta,
 		tasks.ConvertPipelineMeta,
+		tasks.ConvertDeploymentMeta,
 	}
 }
 
diff --git a/plugins/bitbucket/models/pipeline.go b/plugins/bitbucket/models/deployment.go
similarity index 53%
copy from plugins/bitbucket/models/pipeline.go
copy to plugins/bitbucket/models/deployment.go
index 12db320f..cfdbaea4 100644
--- a/plugins/bitbucket/models/pipeline.go
+++ b/plugins/bitbucket/models/deployment.go
@@ -22,21 +22,25 @@ import (
 	"time"
 )
 
-type BitbucketPipeline struct {
-	ConnectionId      uint64 `gorm:"primaryKey"`
-	BitbucketId       string `gorm:"primaryKey"`
-	Status            string `gorm:"type:varchar(100)"`
-	Result            string `gorm:"type:varchar(100)"`
-	RefName           string `gorm:"type:varchar(255)"`
-	WebUrl            string `gorm:"type:varchar(255)"`
-	DurationInSeconds uint64
-
-	BitbucketCreatedOn  *time.Time
-	BitbucketCompleteOn *time.Time
-
+type BitbucketDeployment struct {
+	ConnectionId   uint64 `gorm:"primaryKey"`
+	BitbucketId    string `gorm:"primaryKey"`
+	PipelineId     string `gorm:"type:varchar(255)"`
+	Type           string `gorm:"type:varchar(255)"`
+	Name           string `gorm:"type:varchar(255)"`
+	Key            string `gorm:"type:varchar(255)"`
+	WebUrl         string `gorm:"type:varchar(255)"`
+	Status         string `gorm:"type:varchar(100)"`
+	StateUrl       string `gorm:"type:varchar(255)"`
+	CommitSha      string `gorm:"type:varchar(255)"`
+	CommitUrl      string `gorm:"type:varchar(255)"`
+	CreatedOn      *time.Time
+	StartedOn      *time.Time
+	CompletedOn    *time.Time
+	LastUpdateTime *time.Time
 	common.NoPKModel
 }
 
-func (BitbucketPipeline) TableName() string {
-	return "_tool_bitbucket_pipelines"
+func (BitbucketDeployment) TableName() string {
+	return "_tool_bitbucket_deployments"
 }
diff --git a/plugins/bitbucket/models/migrationscripts/register.go b/plugins/bitbucket/models/migrationscripts/20221013_add_deployment_tables.go
similarity index 57%
copy from plugins/bitbucket/models/migrationscripts/register.go
copy to plugins/bitbucket/models/migrationscripts/20221013_add_deployment_tables.go
index 7218481b..11ab6d7b 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/migrationscripts/20221013_add_deployment_tables.go
@@ -18,13 +18,26 @@ limitations under the License.
 package migrationscripts
 
 import (
-	"github.com/apache/incubator-devlake/migration"
+	"context"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/plugins/bitbucket/models/migrationscripts/archived"
+	"gorm.io/gorm"
 )
 
-// All return all the migration scripts
-func All() []migration.Script {
-	return []migration.Script{
-		new(addInitTables),
-		new(addPipeline20220914),
+type addDeployment20221013 struct{}
+
+func (*addDeployment20221013) Up(ctx context.Context, db *gorm.DB) errors.Error {
+	err := db.Migrator().AutoMigrate(&archived.BitbucketDeployment{})
+	if err != nil {
+		return errors.Convert(err)
 	}
+	return nil
+}
+
+func (*addDeployment20221013) Version() uint64 {
+	return 20221013152349
+}
+
+func (*addDeployment20221013) Name() string {
+	return "bitbucket add _tool_bitbucket_deployments table"
 }
diff --git a/plugins/bitbucket/models/migrationscripts/archived/deployment.go b/plugins/bitbucket/models/migrationscripts/archived/deployment.go
new file mode 100644
index 00000000..2f647320
--- /dev/null
+++ b/plugins/bitbucket/models/migrationscripts/archived/deployment.go
@@ -0,0 +1,46 @@
+/*
+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 archived
+
+import (
+	"github.com/apache/incubator-devlake/models/migrationscripts/archived"
+	"time"
+)
+
+type BitbucketDeployment struct {
+	ConnectionId   uint64 `gorm:"primaryKey"`
+	BitbucketId    string `gorm:"primaryKey"`
+	PipelineId     string `gorm:"type:varchar(255)"`
+	Type           string `gorm:"type:varchar(255)"`
+	Name           string `gorm:"type:varchar(255)"`
+	Key            string `gorm:"type:varchar(255)"`
+	WebUrl         string `gorm:"type:varchar(255)"`
+	Status         string `gorm:"type:varchar(100)"`
+	StateUrl       string `gorm:"type:varchar(255)"`
+	CommitSha      string `gorm:"type:varchar(255)"`
+	CommitUrl      string `gorm:"type:varchar(255)"`
+	CreatedOn      time.Time
+	StartedOn      *time.Time
+	CompletedOn    *time.Time
+	LastUpdateTime *time.Time
+	archived.NoPKModel
+}
+
+func (BitbucketDeployment) TableName() string {
+	return "_tool_bitbucket_deployments"
+}
diff --git a/plugins/bitbucket/models/migrationscripts/register.go b/plugins/bitbucket/models/migrationscripts/register.go
index 7218481b..1fac9090 100644
--- a/plugins/bitbucket/models/migrationscripts/register.go
+++ b/plugins/bitbucket/models/migrationscripts/register.go
@@ -26,5 +26,6 @@ func All() []migration.Script {
 	return []migration.Script{
 		new(addInitTables),
 		new(addPipeline20220914),
+		new(addDeployment20221013),
 	}
 }
diff --git a/plugins/bitbucket/models/pipeline.go b/plugins/bitbucket/models/pipeline.go
index 12db320f..ce48ec6c 100644
--- a/plugins/bitbucket/models/pipeline.go
+++ b/plugins/bitbucket/models/pipeline.go
@@ -40,3 +40,18 @@ type BitbucketPipeline struct {
 func (BitbucketPipeline) TableName() string {
 	return "_tool_bitbucket_pipelines"
 }
+
+const (
+	FAILED      = "FAILED"
+	ERROR       = "ERROR"
+	UNDEPLOYED  = "UNDEPLOYED"
+	STOPPED     = "STOPPED"
+	SKIPPED     = "SKIPPED"
+	SUCCESSFUL  = "SUCCESSFUL"
+	COMPLETED   = "COMPLETED"
+	PAUSED      = "COMPLETED"
+	HALTED      = "HALTED"
+	IN_PROGRESS = "IN_PROGRESS"
+	PENDING     = "PENDING"
+	BUILDING    = "BUILDING"
+)
diff --git a/plugins/bitbucket/tasks/api_common.go b/plugins/bitbucket/tasks/api_common.go
index b931a8a4..f014adc4 100644
--- a/plugins/bitbucket/tasks/api_common.go
+++ b/plugins/bitbucket/tasks/api_common.go
@@ -154,10 +154,3 @@ func ignoreHTTPStatus404(res *http.Response) errors.Error {
 	}
 	return nil
 }
-
-func ignoreHTTPStatus403(res *http.Response) errors.Error {
-	if res.StatusCode == http.StatusForbidden {
-		return helper.ErrIgnoreAndContinue
-	}
-	return nil
-}
diff --git a/plugins/bitbucket/tasks/pipeline_collector.go b/plugins/bitbucket/tasks/deployment_collector.go
similarity index 78%
copy from plugins/bitbucket/tasks/pipeline_collector.go
copy to plugins/bitbucket/tasks/deployment_collector.go
index c4284e7d..43584446 100644
--- a/plugins/bitbucket/tasks/pipeline_collector.go
+++ b/plugins/bitbucket/tasks/deployment_collector.go
@@ -23,29 +23,28 @@ import (
 	"github.com/apache/incubator-devlake/plugins/helper"
 )
 
-const RAW_PIPELINE_TABLE = "bitbucket_api_pipelines"
+const RAW_DEPLOYMENT_TABLE = "bitbucket_api_deployments"
 
-var CollectApiPipelinesMeta = core.SubTaskMeta{
-	Name:             "collectApiPipelines",
-	EntryPoint:       CollectApiPipelines,
+var CollectApiDeploymentsMeta = core.SubTaskMeta{
+	Name:             "collectApiDeployments",
+	EntryPoint:       CollectApiDeployments,
 	EnabledByDefault: true,
-	Description:      "Collect pipeline data from bitbucket api",
+	Description:      "Collect deployment data from bitbucket api",
 	DomainTypes:      []string{core.DOMAIN_TYPE_CICD},
 }
 
-func CollectApiPipelines(taskCtx core.SubTaskContext) errors.Error {
-	rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_PIPELINE_TABLE)
+func CollectApiDeployments(taskCtx core.SubTaskContext) errors.Error {
+	rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_DEPLOYMENT_TABLE)
 
 	collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
 		RawDataSubTaskArgs: *rawDataSubTaskArgs,
 		ApiClient:          data.ApiClient,
 		PageSize:           50,
 		Incremental:        false,
-		UrlTemplate:        "repositories/{{ .Params.Owner }}/{{ .Params.Repo }}/pipelines/",
+		UrlTemplate:        "repositories/{{ .Params.Owner }}/{{ .Params.Repo }}/deployments/",
 		Query:              GetQuery,
 		ResponseParser:     GetRawMessageFromResponse,
 		GetTotalPages:      GetTotalPagesFromResponse,
-		AfterResponse:      ignoreHTTPStatus403, // ignore 403 for CI/CD disable
 	})
 
 	if err != nil {
diff --git a/plugins/bitbucket/tasks/pipeline_convertor.go b/plugins/bitbucket/tasks/deployment_convertor.go
similarity index 57%
copy from plugins/bitbucket/tasks/pipeline_convertor.go
copy to plugins/bitbucket/tasks/deployment_convertor.go
index e3caf9b1..e3e77a50 100644
--- a/plugins/bitbucket/tasks/pipeline_convertor.go
+++ b/plugins/bitbucket/tasks/deployment_convertor.go
@@ -31,28 +31,28 @@ import (
 	"github.com/apache/incubator-devlake/plugins/helper"
 )
 
-var ConvertPipelineMeta = core.SubTaskMeta{
-	Name:             "convertPipelines",
-	EntryPoint:       ConvertPipelines,
+var ConvertDeploymentMeta = core.SubTaskMeta{
+	Name:             "convertDeployments",
+	EntryPoint:       ConvertDeployments,
 	EnabledByDefault: true,
 	Description:      "Convert tool layer table bitbucket_pipeline into domain layer table pipeline",
 	DomainTypes:      []string{core.DOMAIN_TYPE_CROSS},
 }
 
-func ConvertPipelines(taskCtx core.SubTaskContext) errors.Error {
+func ConvertDeployments(taskCtx core.SubTaskContext) errors.Error {
 	db := taskCtx.GetDal()
 	data := taskCtx.GetData().(*BitbucketTaskData)
 
-	cursor, err := db.Cursor(dal.From(bitbucketModels.BitbucketPipeline{}))
+	cursor, err := db.Cursor(dal.From(bitbucketModels.BitbucketDeployment{}))
 	if err != nil {
 		return err
 	}
 	defer cursor.Close()
 
-	pipelineIdGen := didgen.NewDomainIdGenerator(&bitbucketModels.BitbucketPipeline{})
+	pipelineIdGen := didgen.NewDomainIdGenerator(&bitbucketModels.BitbucketDeployment{})
 
 	converter, err := helper.NewDataConverter(helper.DataConverterArgs{
-		InputRowType: reflect.TypeOf(bitbucketModels.BitbucketPipeline{}),
+		InputRowType: reflect.TypeOf(bitbucketModels.BitbucketDeployment{}),
 		Input:        cursor,
 		RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
 			Ctx: taskCtx,
@@ -61,41 +61,49 @@ func ConvertPipelines(taskCtx core.SubTaskContext) errors.Error {
 				Owner:        data.Options.Owner,
 				Repo:         data.Options.Repo,
 			},
-			Table: RAW_PIPELINE_TABLE,
+			Table: RAW_DEPLOYMENT_TABLE,
 		},
 		Convert: func(inputRow interface{}) ([]interface{}, errors.Error) {
-			bitbucketPipeline := inputRow.(*bitbucketModels.BitbucketPipeline)
+			bitbucketDeployment := inputRow.(*bitbucketModels.BitbucketDeployment)
 
-			createdAt := time.Now()
-			if bitbucketPipeline.BitbucketCreatedOn != nil {
-				createdAt = *bitbucketPipeline.BitbucketCreatedOn
+			startedAt := bitbucketDeployment.CreatedOn
+			if bitbucketDeployment.StartedOn != nil {
+				startedAt = bitbucketDeployment.StartedOn
 			}
-
-			domainPipeline := &devops.CICDPipeline{
+			domainDeployment := &devops.CICDTask{
 				DomainEntity: domainlayer.DomainEntity{
-					Id: pipelineIdGen.Generate(data.Options.ConnectionId, bitbucketPipeline.BitbucketId),
+					Id: pipelineIdGen.Generate(data.Options.ConnectionId, bitbucketDeployment.BitbucketId),
 				},
 				Name: didgen.NewDomainIdGenerator(&bitbucketModels.BitbucketPipeline{}).
-					Generate(data.Options.ConnectionId, bitbucketPipeline.RefName),
+					Generate(data.Options.ConnectionId, bitbucketDeployment.Name),
+				PipelineId: bitbucketDeployment.PipelineId,
 				Result: devops.GetResult(&devops.ResultRule{
-					Failed:  []string{"FAILED", "ERROR"},
-					Abort:   []string{"STOPPED", "SKIPPED"},
-					Success: []string{"SUCCESSFUL", "PASSED"},
-					Manual:  []string{"PAUSED", "HALTED"},
+					Failed:  []string{bitbucketModels.FAILED, bitbucketModels.ERROR, bitbucketModels.UNDEPLOYED},
+					Abort:   []string{bitbucketModels.STOPPED, bitbucketModels.SKIPPED},
+					Success: []string{bitbucketModels.SUCCESSFUL, bitbucketModels.COMPLETED},
+					Manual:  []string{bitbucketModels.PAUSED, bitbucketModels.HALTED},
 					Default: devops.SUCCESS,
-				}, bitbucketPipeline.Result),
+				}, bitbucketDeployment.Status),
 				Status: devops.GetStatus(&devops.StatusRule{
-					InProgress: []string{"IN_PROGRESS"},
+					InProgress: []string{bitbucketModels.IN_PROGRESS, bitbucketModels.PENDING, bitbucketModels.BUILDING},
 					Default:    devops.DONE,
-				}, bitbucketPipeline.Status),
-				Type:         "CI/CD",
-				CreatedDate:  createdAt,
-				DurationSec:  bitbucketPipeline.DurationInSeconds,
-				FinishedDate: bitbucketPipeline.BitbucketCompleteOn,
+				}, bitbucketDeployment.Status),
+				Type:         bitbucketDeployment.Type,
+				StartedDate:  *startedAt,
+				FinishedDate: bitbucketDeployment.CompletedOn,
+			}
+			// rebuild the FinishedDate and DurationSec by Status
+			finishedAt := time.Now()
+			if domainDeployment.Status != devops.DONE {
+				domainDeployment.FinishedDate = nil
+			} else if bitbucketDeployment.CompletedOn != nil {
+				finishedAt = *bitbucketDeployment.CompletedOn
 			}
+			durationTime := finishedAt.Sub(*startedAt)
+			domainDeployment.DurationSec = uint64(durationTime.Seconds())
 
 			return []interface{}{
-				domainPipeline,
+				domainDeployment,
 			}, nil
 		},
 	})
diff --git a/plugins/bitbucket/tasks/deployment_extractor.go b/plugins/bitbucket/tasks/deployment_extractor.go
new file mode 100644
index 00000000..87368c84
--- /dev/null
+++ b/plugins/bitbucket/tasks/deployment_extractor.go
@@ -0,0 +1,132 @@
+/*
+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 tasks
+
+import (
+	"encoding/json"
+	"github.com/apache/incubator-devlake/errors"
+	"github.com/apache/incubator-devlake/plugins/bitbucket/models"
+	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/helper"
+	"time"
+)
+
+type bitbucketApiDeploymentsResponse struct {
+	Type   string `json:"type"`
+	Number int    `json:"number"`
+	UUID   string `json:"uuid"`
+	Key    string `json:"key"`
+	Step   struct {
+		UUID string `json:"uuid"`
+	} `json:"step"`
+	Environment struct {
+		UUID string `json:"uuid"`
+	} `json:"environment"`
+	Release struct {
+		Type     string `json:"type"`
+		UUID     string `json:"uuid"`
+		Pipeline struct {
+			UUID string `json:"uuid"`
+			Type string `json:"type"`
+		} `json:"pipeline"`
+		Key    string `json:"key"`
+		Name   string `json:"name"`
+		URL    string `json:"url"`
+		Commit struct {
+			Type  string `json:"type"`
+			Hash  string `json:"hash"`
+			Links struct {
+				Self struct {
+					Href string `json:"href"`
+				} `json:"self"`
+				HTML struct {
+					Href string `json:"href"`
+				} `json:"html"`
+			} `json:"links"`
+		} `json:"commit"`
+		CreatedOn *time.Time `json:"created_on"`
+	} `json:"release"`
+	State struct {
+		Type   string `json:"type"`
+		Name   string `json:"name"`
+		URL    string `json:"url"`
+		Status struct {
+			Type string `json:"type"`
+			Name string `json:"name"`
+		} `json:"status"`
+		StartedOn   *time.Time `json:"started_on"`
+		CompletedOn *time.Time `json:"completed_on"`
+	} `json:"state"`
+	LastUpdateTime *time.Time `json:"last_update_time"`
+	Version        int        `json:"version"`
+}
+
+var ExtractApiDeploymentsMeta = core.SubTaskMeta{
+	Name:             "extractApiDeployments",
+	EntryPoint:       ExtractApiDeployments,
+	EnabledByDefault: true,
+	Description:      "Extract raw deployments data into tool layer table BitbucketDeployment",
+	DomainTypes:      []string{core.DOMAIN_TYPE_CICD},
+}
+
+func ExtractApiDeployments(taskCtx core.SubTaskContext) errors.Error {
+	rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_DEPLOYMENT_TABLE)
+
+	extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+		RawDataSubTaskArgs: *rawDataSubTaskArgs,
+		Extract: func(row *helper.RawData) ([]interface{}, errors.Error) {
+			bitbucketApiDeployments := &bitbucketApiDeploymentsResponse{}
+			err := errors.Convert(json.Unmarshal(row.Data, bitbucketApiDeployments))
+			if err != nil {
+				return nil, err
+			}
+
+			bitbucketDeployment := &models.BitbucketDeployment{
+				ConnectionId:   data.Options.ConnectionId,
+				BitbucketId:    bitbucketApiDeployments.UUID,
+				PipelineId:     bitbucketApiDeployments.Release.Pipeline.UUID,
+				Type:           bitbucketApiDeployments.Type,
+				Name:           bitbucketApiDeployments.Release.Name,
+				Key:            bitbucketApiDeployments.Release.Key,
+				WebUrl:         bitbucketApiDeployments.Release.URL,
+				CommitSha:      bitbucketApiDeployments.Release.Commit.Hash,
+				CommitUrl:      bitbucketApiDeployments.Release.Commit.Links.HTML.Href,
+				Status:         bitbucketApiDeployments.State.Name,
+				StateUrl:       bitbucketApiDeployments.State.URL,
+				CreatedOn:      bitbucketApiDeployments.Release.CreatedOn,
+				StartedOn:      bitbucketApiDeployments.State.StartedOn,
+				CompletedOn:    bitbucketApiDeployments.State.CompletedOn,
+				LastUpdateTime: bitbucketApiDeployments.LastUpdateTime,
+			}
+			if err != nil {
+				return nil, err
+			}
+
+			results := make([]interface{}, 0, 2)
+			results = append(results, bitbucketDeployment)
+
+			return results, nil
+		},
+	})
+
+	if err != nil {
+		return err
+	}
+
+	return extractor.Execute()
+}
diff --git a/plugins/bitbucket/tasks/pipeline_collector.go b/plugins/bitbucket/tasks/pipeline_collector.go
index c4284e7d..60388918 100644
--- a/plugins/bitbucket/tasks/pipeline_collector.go
+++ b/plugins/bitbucket/tasks/pipeline_collector.go
@@ -45,7 +45,6 @@ func CollectApiPipelines(taskCtx core.SubTaskContext) errors.Error {
 		Query:              GetQuery,
 		ResponseParser:     GetRawMessageFromResponse,
 		GetTotalPages:      GetTotalPagesFromResponse,
-		AfterResponse:      ignoreHTTPStatus403, // ignore 403 for CI/CD disable
 	})
 
 	if err != nil {
diff --git a/plugins/bitbucket/tasks/pipeline_convertor.go b/plugins/bitbucket/tasks/pipeline_convertor.go
index e3caf9b1..7e75d7ad 100644
--- a/plugins/bitbucket/tasks/pipeline_convertor.go
+++ b/plugins/bitbucket/tasks/pipeline_convertor.go
@@ -78,14 +78,14 @@ func ConvertPipelines(taskCtx core.SubTaskContext) errors.Error {
 				Name: didgen.NewDomainIdGenerator(&bitbucketModels.BitbucketPipeline{}).
 					Generate(data.Options.ConnectionId, bitbucketPipeline.RefName),
 				Result: devops.GetResult(&devops.ResultRule{
-					Failed:  []string{"FAILED", "ERROR"},
-					Abort:   []string{"STOPPED", "SKIPPED"},
-					Success: []string{"SUCCESSFUL", "PASSED"},
-					Manual:  []string{"PAUSED", "HALTED"},
+					Failed:  []string{bitbucketModels.FAILED, bitbucketModels.ERROR, bitbucketModels.UNDEPLOYED},
+					Abort:   []string{bitbucketModels.STOPPED, bitbucketModels.SKIPPED},
+					Success: []string{bitbucketModels.SUCCESSFUL, bitbucketModels.COMPLETED},
+					Manual:  []string{bitbucketModels.PAUSED, bitbucketModels.HALTED},
 					Default: devops.SUCCESS,
 				}, bitbucketPipeline.Result),
 				Status: devops.GetStatus(&devops.StatusRule{
-					InProgress: []string{"IN_PROGRESS"},
+					InProgress: []string{bitbucketModels.IN_PROGRESS, bitbucketModels.PENDING, bitbucketModels.BUILDING},
 					Default:    devops.DONE,
 				}, bitbucketPipeline.Status),
 				Type:         "CI/CD",