You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ma...@apache.org on 2023/05/31 10:57:51 UTC

[incubator-devlake] branch main updated: Cleaning up scope config refactor (#5332)

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

mappjzc 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 a79da26b6 Cleaning up scope config refactor (#5332)
a79da26b6 is described below

commit a79da26b6a46af9b28bc89de1544a4fb9ee04df1
Author: Klesh Wong <zh...@merico.dev>
AuthorDate: Wed May 31 18:57:46 2023 +0800

    Cleaning up scope config refactor (#5332)
    
    * fix: missed entities refactor
    
    * fix: rename github transformation_rule
    
    * fix: format linting
    
    * fix: cleaning up github/jenkins/jira/tapd bp api
    
    * fix: bitbucket bpv200 unit test
---
 .../plugins/bitbucket/api/blueprint_V200_test.go   | 12 +++----
 backend/plugins/bitbucket/api/blueprint_v200.go    | 21 +++++++----
 backend/plugins/github/api/blueprint_v200.go       |  1 -
 .../{transformation_rule.go => scope_config.go}    |  0
 backend/plugins/jenkins/api/blueprint_v200.go      | 42 +++++++++++++++++++---
 backend/plugins/jenkins/api/blueprint_v200_test.go | 28 ++++++++++-----
 backend/plugins/jenkins/models/job.go              | 24 ++++++-------
 backend/plugins/jira/api/blueprint_v200.go         | 14 ++++----
 backend/plugins/jira/models/board.go               | 16 ++++-----
 backend/plugins/tapd/api/blueprint_v200.go         | 14 ++++----
 backend/plugins/trello/api/scope.go                | 11 ------
 11 files changed, 111 insertions(+), 72 deletions(-)

diff --git a/backend/plugins/bitbucket/api/blueprint_V200_test.go b/backend/plugins/bitbucket/api/blueprint_V200_test.go
index 453d291a3..0ebe39602 100644
--- a/backend/plugins/bitbucket/api/blueprint_V200_test.go
+++ b/backend/plugins/bitbucket/api/blueprint_V200_test.go
@@ -61,8 +61,7 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 	// Refresh Global Variables and set the sql mock
 	basicRes = NewMockBasicRes()
 	bs := &plugin.BlueprintScopeV200{
-		Entities: []string{"CODE", "TICKET"},
-		Id:       "1",
+		Id: "1",
 	}
 	bpScopes := make([]*plugin.BlueprintScopeV200, 0)
 	bpScopes = append(bpScopes, bs)
@@ -142,6 +141,7 @@ func NewMockBasicRes() *mockcontext.BasicRes {
 
 	testScopeConfig := &models.BitbucketScopeConfig{
 		ScopeConfig: common.ScopeConfig{
+			Entities: []string{"CODE", "TICKET"},
 			Model: common.Model{
 				ID: 1,
 			},
@@ -157,15 +157,15 @@ func NewMockBasicRes() *mockcontext.BasicRes {
 	mockRes := new(mockcontext.BasicRes)
 	mockDal := new(mockdal.Dal)
 
-	mockDal.On("First", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+	mockDal.On("First", mock.AnythingOfType("*models.BitbucketRepo"), mock.Anything).Run(func(args mock.Arguments) {
 		dst := args.Get(0).(*models.BitbucketRepo)
 		*dst = *testBitbucketRepo
-	}).Return(nil).Once()
+	}).Return(nil)
 
-	mockDal.On("First", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+	mockDal.On("First", mock.AnythingOfType("*models.BitbucketScopeConfig"), mock.Anything).Run(func(args mock.Arguments) {
 		dst := args.Get(0).(*models.BitbucketScopeConfig)
 		*dst = *testScopeConfig
-	}).Return(nil).Once()
+	}).Return(nil)
 
 	mockRes.On("GetDal").Return(mockDal)
 	mockRes.On("GetConfig", mock.Anything).Return("")
diff --git a/backend/plugins/bitbucket/api/blueprint_v200.go b/backend/plugins/bitbucket/api/blueprint_v200.go
index 98d959e1d..421bac0fa 100644
--- a/backend/plugins/bitbucket/api/blueprint_v200.go
+++ b/backend/plugins/bitbucket/api/blueprint_v200.go
@@ -130,7 +130,7 @@ func makeDataSourcePipelinePlanV200(
 		}
 
 		// add gitex stage
-		if utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CODE) {
+		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CODE) {
 			cloneUrl, err := errors.Convert01(url.Parse(repo.CloneUrl))
 			if err != nil {
 				return nil, err
@@ -153,16 +153,23 @@ func makeDataSourcePipelinePlanV200(
 
 func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connection *models.BitbucketConnection) ([]plugin.Scope, errors.Error) {
 	scopes := make([]plugin.Scope, 0)
+	db := basicRes.GetDal()
 	for _, bpScope := range bpScopes {
 		repo := &models.BitbucketRepo{}
 		// get repo from db
-		err := basicRes.GetDal().First(repo, dal.Where(`connection_id = ? AND bitbucket_id = ?`, connection.ID, bpScope.Id))
+		err := db.First(repo, dal.Where(`connection_id = ? AND bitbucket_id = ?`, connection.ID, bpScope.Id))
 		if err != nil {
 			return nil, errors.Default.Wrap(err, fmt.Sprintf("fail to find repo%s", bpScope.Id))
 		}
-		if utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CODE_REVIEW) ||
-			utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CODE) ||
-			utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CROSS) {
+		scopeConfig := &models.BitbucketScopeConfig{}
+		// get scope configs from db
+		err = db.First(scopeConfig, dal.Where(`id = ?`, repo.ScopeConfigId))
+		if err != nil && !db.IsErrorNotFound(err) {
+			return nil, err
+		}
+		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CODE_REVIEW) ||
+			utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CODE) ||
+			utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CROSS) {
 			// if we don't need to collect gitex, we need to add repo to scopes here
 			scopeRepo := &code.Repo{
 				DomainEntity: domainlayer.DomainEntity{
@@ -173,7 +180,7 @@ func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connection *models.Bi
 			scopes = append(scopes, scopeRepo)
 		}
 		// add cicd_scope to scopes
-		if utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CICD) {
+		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CICD) {
 			scopeCICD := &devops.CicdScope{
 				DomainEntity: domainlayer.DomainEntity{
 					Id: didgen.NewDomainIdGenerator(&models.BitbucketRepo{}).Generate(connection.ID, repo.BitbucketId),
@@ -183,7 +190,7 @@ func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connection *models.Bi
 			scopes = append(scopes, scopeCICD)
 		}
 		// add board to scopes
-		if utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_TICKET) {
+		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_TICKET) {
 			scopeTicket := &ticket.Board{
 				DomainEntity: domainlayer.DomainEntity{
 					Id: didgen.NewDomainIdGenerator(&models.BitbucketRepo{}).Generate(connection.ID, repo.BitbucketId),
diff --git a/backend/plugins/github/api/blueprint_v200.go b/backend/plugins/github/api/blueprint_v200.go
index e151bd844..e0a0f4590 100644
--- a/backend/plugins/github/api/blueprint_v200.go
+++ b/backend/plugins/github/api/blueprint_v200.go
@@ -175,7 +175,6 @@ func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connection *models.Gi
 			return nil, err
 		}
 
-		basicRes.GetDal().First(scopeConfig, dal.Where(`id = ?`, githubRepo.ScopeConfigId))
 		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CODE_REVIEW) ||
 			utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CODE) ||
 			utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CROSS) {
diff --git a/backend/plugins/github/api/transformation_rule.go b/backend/plugins/github/api/scope_config.go
similarity index 100%
rename from backend/plugins/github/api/transformation_rule.go
rename to backend/plugins/github/api/scope_config.go
diff --git a/backend/plugins/jenkins/api/blueprint_v200.go b/backend/plugins/jenkins/api/blueprint_v200.go
index c820f17ac..c98391244 100644
--- a/backend/plugins/jenkins/api/blueprint_v200.go
+++ b/backend/plugins/jenkins/api/blueprint_v200.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/apache/incubator-devlake/core/context"
 	"github.com/apache/incubator-devlake/core/dal"
 	"github.com/apache/incubator-devlake/core/errors"
 	"github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -34,11 +35,11 @@ import (
 
 func MakeDataSourcePipelinePlanV200(subtaskMetas []plugin.SubTaskMeta, connectionId uint64, bpScopes []*plugin.BlueprintScopeV200, syncPolicy *plugin.BlueprintSyncPolicy) (plugin.PipelinePlan, []plugin.Scope, errors.Error) {
 	plan := make(plugin.PipelinePlan, len(bpScopes))
-	plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, plan, bpScopes, connectionId, syncPolicy)
+	plan, err := makeDataSourcePipelinePlanV200(basicRes, subtaskMetas, plan, bpScopes, connectionId, syncPolicy)
 	if err != nil {
 		return nil, nil, err
 	}
-	scopes, err := makeScopesV200(bpScopes, connectionId)
+	scopes, err := makeScopesV200(basicRes, bpScopes, connectionId)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -46,7 +47,23 @@ func MakeDataSourcePipelinePlanV200(subtaskMetas []plugin.SubTaskMeta, connectio
 	return plan, scopes, nil
 }
 
+func getScopeConfigByScopeId(basicRes context.BasicRes, connectionId uint64, scopeId string) (*models.JenkinsScopeConfig, errors.Error) {
+	db := basicRes.GetDal()
+	scopeConfig := &models.JenkinsScopeConfig{}
+	err := db.First(scopeConfig,
+		dal.Select("c.*"),
+		dal.From("_tool_jenkins_scope_configs c"),
+		dal.Join("LEFT JOIN _tool_jenkins_jobs s ON (s.scope_config_id = c.id)"),
+		dal.Where("s.connection_id = ? AND s.full_name = ?", connectionId, scopeId),
+	)
+	if err != nil {
+		return nil, err
+	}
+	return scopeConfig, nil
+}
+
 func makeDataSourcePipelinePlanV200(
+	basicRes context.BasicRes,
 	subtaskMetas []plugin.SubTaskMeta,
 	plan plugin.PipelinePlan,
 	bpScopes []*plugin.BlueprintScopeV200,
@@ -67,7 +84,13 @@ func makeDataSourcePipelinePlanV200(
 		if syncPolicy.TimeAfter != nil {
 			options["timeAfter"] = syncPolicy.TimeAfter.Format(time.RFC3339)
 		}
-		subtasks, err := helper.MakePipelinePlanSubtasks(subtaskMetas, bpScope.Entities)
+
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
+		if err != nil {
+			return nil, err
+		}
+
+		subtasks, err := helper.MakePipelinePlanSubtasks(subtaskMetas, scopeConfig.Entities)
 		if err != nil {
 			return nil, err
 		}
@@ -82,7 +105,11 @@ func makeDataSourcePipelinePlanV200(
 	return plan, nil
 }
 
-func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connectionId uint64) ([]plugin.Scope, errors.Error) {
+func makeScopesV200(
+	basicRes context.BasicRes,
+	bpScopes []*plugin.BlueprintScopeV200,
+	connectionId uint64,
+) ([]plugin.Scope, errors.Error) {
 	scopes := make([]plugin.Scope, 0)
 	for _, bpScope := range bpScopes {
 		jenkinsJob := &models.JenkinsJob{}
@@ -94,8 +121,13 @@ func makeScopesV200(bpScopes []*plugin.BlueprintScopeV200, connectionId uint64)
 			return nil, errors.Default.Wrap(err, fmt.Sprintf("fail to find jenkinsJob%s", bpScope.Id))
 		}
 
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
+		if err != nil {
+			return nil, err
+		}
+
 		// add cicd_scope to scopes
-		if utils.StringsContains(bpScope.Entities, plugin.DOMAIN_TYPE_CICD) {
+		if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_CICD) {
 			scopeCICD := &devops.CicdScope{
 				DomainEntity: domainlayer.DomainEntity{
 					Id: didgen.NewDomainIdGenerator(&models.JenkinsJob{}).Generate(connectionId, jenkinsJob.FullName),
diff --git a/backend/plugins/jenkins/api/blueprint_v200_test.go b/backend/plugins/jenkins/api/blueprint_v200_test.go
index 3461e9af1..6b203e307 100644
--- a/backend/plugins/jenkins/api/blueprint_v200_test.go
+++ b/backend/plugins/jenkins/api/blueprint_v200_test.go
@@ -18,6 +18,9 @@ limitations under the License.
 package api
 
 import (
+	"testing"
+
+	"github.com/apache/incubator-devlake/core/models/common"
 	"github.com/apache/incubator-devlake/core/models/domainlayer"
 	"github.com/apache/incubator-devlake/core/models/domainlayer/devops"
 	"github.com/apache/incubator-devlake/core/plugin"
@@ -27,7 +30,6 @@ import (
 	"github.com/apache/incubator-devlake/plugins/jenkins/models"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
-	"testing"
 )
 
 func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
@@ -36,9 +38,8 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 	err := plugin.RegisterPlugin("jenkins", mockMeta)
 	assert.Nil(t, err)
 	bs := &plugin.BlueprintScopeV200{
-		Entities: []string{"CICD"},
-		Id:       "a/b/ccc",
-		Name:     "",
+		Id:   "a/b/ccc",
+		Name: "",
 	}
 	syncPolicy := &plugin.BlueprintSyncPolicy{}
 	bpScopes := make([]*plugin.BlueprintScopeV200, 0)
@@ -46,10 +47,10 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 	basicRes = NewMockBasicRes()
 	plan := make(plugin.PipelinePlan, len(bpScopes))
-	plan, err = makeDataSourcePipelinePlanV200(nil, plan, bpScopes, 1, syncPolicy)
+	plan, err = makeDataSourcePipelinePlanV200(basicRes, nil, plan, bpScopes, 1, syncPolicy)
 	assert.Nil(t, err)
 	basicRes = NewMockBasicRes()
-	scopes, err := makeScopesV200(bpScopes, 1)
+	scopes, err := makeScopesV200(basicRes, bpScopes, 1)
 	assert.Nil(t, err)
 
 	expectPlan := plugin.PipelinePlan{
@@ -84,13 +85,24 @@ func NewMockBasicRes() *mockcontext.BasicRes {
 		ConnectionId: 1,
 		FullName:     "a/b/ccc",
 	}
+
+	scopeConfig := &models.JenkinsScopeConfig{
+		ScopeConfig: common.ScopeConfig{
+			Entities: []string{"CICD"},
+		},
+	}
+
 	mockRes := new(mockcontext.BasicRes)
 	mockDal := new(mockdal.Dal)
 
-	mockDal.On("First", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+	mockDal.On("First", mock.AnythingOfType("*models.JenkinsScopeConfig"), mock.Anything).Run(func(args mock.Arguments) {
+		dst := args.Get(0).(*models.JenkinsScopeConfig)
+		*dst = *scopeConfig
+	}).Return(nil)
+	mockDal.On("First", mock.AnythingOfType("*models.JenkinsJob"), mock.Anything).Run(func(args mock.Arguments) {
 		dst := args.Get(0).(*models.JenkinsJob)
 		*dst = *jenkinsJob
-	}).Return(nil).Once()
+	}).Return(nil)
 
 	mockRes.On("GetDal").Return(mockDal)
 	mockRes.On("GetConfig", mock.Anything).Return("")
diff --git a/backend/plugins/jenkins/models/job.go b/backend/plugins/jenkins/models/job.go
index b9c854e2a..197211577 100644
--- a/backend/plugins/jenkins/models/job.go
+++ b/backend/plugins/jenkins/models/job.go
@@ -23,18 +23,18 @@ import (
 
 // JenkinsJob db entity for jenkins job
 type JenkinsJob struct {
-	ConnectionId         uint64 `gorm:"primaryKey" mapstructure:"connectionId,omitempty" validate:"required" json:"connectionId"`
-	FullName             string `gorm:"primaryKey;type:varchar(255)" mapstructure:"jobFullName" validate:"required" json:"jobFullName"` // "path1/path2/job name"
-	ScopeConfigId uint64 `mapstructure:"scopeConfigId,omitempty" json:"scopeConfigId,omitempty"`
-	Name                 string `gorm:"index;type:varchar(255)" mapstructure:"name" json:"name"`     // scope name now is same to `jobFullName`
-	Path                 string `gorm:"index;type:varchar(511)" mapstructure:"-,omitempty" json:"-"` // "job/path1/job/path2"
-	Class                string `gorm:"type:varchar(255)" mapstructure:"class,omitempty" json:"class"`
-	Color                string `gorm:"type:varchar(255)" mapstructure:"color,omitempty" json:"color"`
-	Base                 string `gorm:"type:varchar(255)" mapstructure:"base,omitempty" json:"base"`
-	Url                  string `mapstructure:"url,omitempty" json:"url"`
-	Description          string `mapstructure:"description,omitempty" json:"description"`
-	PrimaryView          string `gorm:"type:varchar(255)" mapstructure:"primaryView,omitempty" json:"primaryView"`
-	common.NoPKModel     `json:"-" mapstructure:"-"`
+	ConnectionId     uint64 `gorm:"primaryKey" mapstructure:"connectionId,omitempty" validate:"required" json:"connectionId"`
+	FullName         string `gorm:"primaryKey;type:varchar(255)" mapstructure:"jobFullName" validate:"required" json:"jobFullName"` // "path1/path2/job name"
+	ScopeConfigId    uint64 `mapstructure:"scopeConfigId,omitempty" json:"scopeConfigId,omitempty"`
+	Name             string `gorm:"index;type:varchar(255)" mapstructure:"name" json:"name"`     // scope name now is same to `jobFullName`
+	Path             string `gorm:"index;type:varchar(511)" mapstructure:"-,omitempty" json:"-"` // "job/path1/job/path2"
+	Class            string `gorm:"type:varchar(255)" mapstructure:"class,omitempty" json:"class"`
+	Color            string `gorm:"type:varchar(255)" mapstructure:"color,omitempty" json:"color"`
+	Base             string `gorm:"type:varchar(255)" mapstructure:"base,omitempty" json:"base"`
+	Url              string `mapstructure:"url,omitempty" json:"url"`
+	Description      string `mapstructure:"description,omitempty" json:"description"`
+	PrimaryView      string `gorm:"type:varchar(255)" mapstructure:"primaryView,omitempty" json:"primaryView"`
+	common.NoPKModel `json:"-" mapstructure:"-"`
 }
 
 func (JenkinsJob) TableName() string {
diff --git a/backend/plugins/jira/api/blueprint_v200.go b/backend/plugins/jira/api/blueprint_v200.go
index 66434aade..26b9a115d 100644
--- a/backend/plugins/jira/api/blueprint_v200.go
+++ b/backend/plugins/jira/api/blueprint_v200.go
@@ -47,14 +47,14 @@ func MakeDataSourcePipelinePlanV200(subtaskMetas []plugin.SubTaskMeta, connectio
 	return plan, scopes, nil
 }
 
-func getScopeConfigByScopeId(basicRes context.BasicRes, scopeId string) (*models.JiraScopeConfig, errors.Error) {
+func getScopeConfigByScopeId(basicRes context.BasicRes, connectionId uint64, scopeId string) (*models.JiraScopeConfig, errors.Error) {
 	db := basicRes.GetDal()
 	scopeConfig := &models.JiraScopeConfig{}
 	err := db.First(scopeConfig,
-		dal.Select("sc.*"),
-		dal.From("_tool_jira_scope_configs sc"),
-		dal.Join("LEFT JOIN _tool_jira_boards b ON (b.scope_config_id = sc.id)"),
-		dal.Where("b.board_id = ?", scopeId),
+		dal.Select("c.*"),
+		dal.From("_tool_jira_scope_configs c"),
+		dal.Join("LEFT JOIN _tool_jira_boards s ON (s.scope_config_id = c.id)"),
+		dal.Where("s.connection_id = ? AND s.board_id = ?", connectionId, scopeId),
 	)
 	if err != nil {
 		return nil, err
@@ -83,7 +83,7 @@ func makeDataSourcePipelinePlanV200(
 			options["timeAfter"] = syncPolicy.TimeAfter.Format(time.RFC3339)
 		}
 
-		scopeConfig, err := getScopeConfigByScopeId(basicRes, bpScope.Id)
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
 		if err != nil {
 			return nil, err
 		}
@@ -118,7 +118,7 @@ func makeScopesV200(
 		if err != nil {
 			return nil, errors.Default.Wrap(err, fmt.Sprintf("fail to find board %s", bpScope.Id))
 		}
-		scopeConfig, err := getScopeConfigByScopeId(basicRes, bpScope.Id)
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
 		if err != nil {
 			return nil, err
 		}
diff --git a/backend/plugins/jira/models/board.go b/backend/plugins/jira/models/board.go
index d5e33ebe4..c87fc5620 100644
--- a/backend/plugins/jira/models/board.go
+++ b/backend/plugins/jira/models/board.go
@@ -22,14 +22,14 @@ import (
 )
 
 type JiraBoard struct {
-	common.NoPKModel     `json:"-" mapstructure:"-"`
-	ConnectionId         uint64 `json:"connectionId" mapstructure:"connectionId" validate:"required" gorm:"primaryKey"`
-	BoardId              uint64 `json:"boardId" mapstructure:"boardId" validate:"required" gorm:"primaryKey"`
-	ScopeConfigId uint64 `json:"scopeConfigId,omitempty" mapstructure:"scopeConfigId"`
-	ProjectId            uint   `json:"projectId" mapstructure:"projectId"`
-	Name                 string `json:"name" mapstructure:"name" gorm:"type:varchar(255)"`
-	Self                 string `json:"self" mapstructure:"self" gorm:"type:varchar(255)"`
-	Type                 string `json:"type" mapstructure:"type" gorm:"type:varchar(100)"`
+	common.NoPKModel `json:"-" mapstructure:"-"`
+	ConnectionId     uint64 `json:"connectionId" mapstructure:"connectionId" validate:"required" gorm:"primaryKey"`
+	BoardId          uint64 `json:"boardId" mapstructure:"boardId" validate:"required" gorm:"primaryKey"`
+	ScopeConfigId    uint64 `json:"scopeConfigId,omitempty" mapstructure:"scopeConfigId"`
+	ProjectId        uint   `json:"projectId" mapstructure:"projectId"`
+	Name             string `json:"name" mapstructure:"name" gorm:"type:varchar(255)"`
+	Self             string `json:"self" mapstructure:"self" gorm:"type:varchar(255)"`
+	Type             string `json:"type" mapstructure:"type" gorm:"type:varchar(100)"`
 }
 
 func (JiraBoard) TableName() string {
diff --git a/backend/plugins/tapd/api/blueprint_v200.go b/backend/plugins/tapd/api/blueprint_v200.go
index 5ec8ad7ef..648a269c5 100644
--- a/backend/plugins/tapd/api/blueprint_v200.go
+++ b/backend/plugins/tapd/api/blueprint_v200.go
@@ -48,14 +48,14 @@ func MakeDataSourcePipelinePlanV200(subtaskMetas []plugin.SubTaskMeta, connectio
 	return plan, scopes, nil
 }
 
-func getScopeConfigByScopeId(basicRes context.BasicRes, scopeId string) (*models.TapdScopeConfig, errors.Error) {
+func getScopeConfigByScopeId(basicRes context.BasicRes, connectionId uint64, scopeId string) (*models.TapdScopeConfig, errors.Error) {
 	db := basicRes.GetDal()
 	scopeConfig := &models.TapdScopeConfig{}
 	err := db.First(scopeConfig,
-		dal.Select("sc.*"),
-		dal.From("_tool_tapd_scope_configs sc"),
-		dal.Join("LEFT JOIN _tool_tapd_workspaces b ON (b.scope_config_id = sc.id)"),
-		dal.Where("b.id = ?", scopeId),
+		dal.Select("c.*"),
+		dal.From("_tool_tapd_scope_configs c"),
+		dal.Join("LEFT JOIN _tool_tapd_workspaces s ON (s.scope_config_id = c.id)"),
+		dal.Where("s.connection_id = ? AND s.id = ?", connectionId, scopeId),
 	)
 	if err != nil {
 		return nil, err
@@ -88,7 +88,7 @@ func makeDataSourcePipelinePlanV200(
 			options["timeAfter"] = syncPolicy.TimeAfter.Format(time.RFC3339)
 		}
 
-		scopeConfig, err := getScopeConfigByScopeId(basicRes, bpScope.Id)
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
 		if err != nil {
 			return nil, err
 		}
@@ -124,7 +124,7 @@ func makeScopesV200(
 			return nil, errors.Default.Wrap(err, fmt.Sprintf("fail to find wrokspace %s", bpScope.Id))
 		}
 
-		scopeConfig, err := getScopeConfigByScopeId(basicRes, bpScope.Id)
+		scopeConfig, err := getScopeConfigByScopeId(basicRes, connectionId, bpScope.Id)
 		if err != nil {
 			return nil, err
 		}
diff --git a/backend/plugins/trello/api/scope.go b/backend/plugins/trello/api/scope.go
index b683d3fcf..45db6372c 100644
--- a/backend/plugins/trello/api/scope.go
+++ b/backend/plugins/trello/api/scope.go
@@ -18,21 +18,10 @@ limitations under the License.
 package api
 
 import (
-	"github.com/apache/incubator-devlake/plugins/trello/models"
-
 	"github.com/apache/incubator-devlake/core/errors"
 	"github.com/apache/incubator-devlake/core/plugin"
 )
 
-type apiBoard struct {
-	models.TrelloBoard
-	ScopeConfigName string `json:"scopeConfigName,omitempty"`
-}
-
-type req struct {
-	Data []*models.TrelloBoard `json:"data"`
-}
-
 // PutScope create or update trello board
 // @Summary create or update trello board
 // @Description Create or update trello board