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

abeizn 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 52ef3ca09 refactor: extract scope common fields to `common.Scope` 
(#6143)
52ef3ca09 is described below

commit 52ef3ca09b5ed135311be43f3147c6f7373d19a5
Author: Klesh Wong <[email protected]>
AuthorDate: Mon Sep 25 18:08:25 2023 +0800

    refactor: extract scope common fields to `common.Scope` (#6143)
    
    * refactor: extract scope common fields to `common.Scope`
    
    * fix: linting
    
    * fix: remove useless index name
---
 backend/core/models/common/base.go                 | 49 +++++++++------
 ...connection_abstract.go => plugin_datasource.go} | 55 +++++++++++++++++
 backend/core/plugin/plugin_scope_abstract.go       | 58 ------------------
 backend/helpers/pluginhelper/api/connection.go     |  4 ++
 .../helpers/pluginhelper/api/scope_helper_test.go  | 43 ++++++++------
 backend/plugins/bamboo/api/blueprint_V200_test.go  | 13 ++--
 backend/plugins/bamboo/models/plan.go              |  4 +-
 .../plugins/bitbucket/api/blueprint_V200_test.go   | 12 ++--
 backend/plugins/bitbucket/models/repo.go           | 22 ++++---
 backend/plugins/circleci/models/project.go         |  5 +-
 ...register.go => 20230922_add_scope_config_id.go} | 35 +++++++++--
 .../gitee/models/migrationscripts/register.go      |  1 +
 backend/plugins/gitee/models/repo.go               |  3 +-
 backend/plugins/gitee/tasks/repo_extractor.go      | 22 +++----
 backend/plugins/github/api/blueprint_V200_test.go  | 30 ++++++++--
 backend/plugins/github/models/repo.go              | 28 ++++-----
 backend/plugins/github/models/scope_config.go      |  9 ++-
 backend/plugins/gitlab/api/blueprint_V200_test.go  |  6 +-
 backend/plugins/gitlab/models/project.go           |  5 +-
 backend/plugins/jenkins/api/blueprint_v200_test.go |  6 +-
 backend/plugins/jenkins/models/job.go              | 22 ++++---
 backend/plugins/jira/api/blueprint_v200_test.go    |  8 ++-
 backend/plugins/jira/models/board.go               | 14 ++---
 backend/plugins/pagerduty/e2e/incident_test.go     | 10 ++--
 backend/plugins/pagerduty/models/scope_config.go   |  2 -
 backend/plugins/pagerduty/models/service.go        |  9 ++-
 .../plugins/pagerduty/tasks/incidents_extractor.go | 12 ++--
 .../plugins/sonarqube/api/blueprint_v200_test.go   |  9 ++-
 .../plugins/sonarqube/models/sonarqube_project.go  |  3 +-
 backend/plugins/tapd/api/blueprint_v200_test.go    |  8 ++-
 backend/plugins/tapd/api/remote.go                 | 23 ++++----
 backend/plugins/tapd/models/workspace.go           | 50 +++++-----------
 backend/plugins/trello/models/board.go             |  9 ++-
 backend/plugins/zentao/api/blueprint_V200_test.go  | 12 ++--
 backend/plugins/zentao/models/project.go           | 69 +++++++++++-----------
 backend/server/services/remote/models/models.go    | 10 ++++
 36 files changed, 371 insertions(+), 309 deletions(-)

diff --git a/backend/core/models/common/base.go 
b/backend/core/models/common/base.go
index a6a48bd47..0f4ec757c 100644
--- a/backend/core/models/common/base.go
+++ b/backend/core/models/common/base.go
@@ -18,7 +18,6 @@ limitations under the License.
 package common
 
 import (
-       "regexp"
        "time"
 )
 
@@ -47,17 +46,6 @@ type Updater struct {
        UpdaterEmail string `json:"updaterEmail"`
 }
 
-type ScopeConfig struct {
-       Model
-       Entities []string `gorm:"type:json;serializer:json" json:"entities" 
mapstructure:"entities"`
-}
-
-type NoPKModel struct {
-       CreatedAt     time.Time `json:"createdAt" mapstructure:"createdAt"`
-       UpdatedAt     time.Time `json:"updatedAt" mapstructure:"updatedAt"`
-       RawDataOrigin `swaggerignore:"true"`
-}
-
 // embedded fields for tool layer tables
 type RawDataOrigin struct {
        // can be used for flushing outdated records from table
@@ -77,6 +65,12 @@ func (c *RawDataOrigin) GetRawDataOrigin() *RawDataOrigin {
        return c
 }
 
+type NoPKModel struct {
+       CreatedAt     time.Time `json:"createdAt" mapstructure:"createdAt"`
+       UpdatedAt     time.Time `json:"updatedAt" mapstructure:"updatedAt"`
+       RawDataOrigin `swaggerignore:"true"`
+}
+
 func NewNoPKModel() NoPKModel {
        now := time.Now()
        return NoPKModel{
@@ -85,10 +79,31 @@ func NewNoPKModel() NoPKModel {
        }
 }
 
-var (
-       DUPLICATE_REGEX = regexp.MustCompile(`(?i)\bduplicate\b`)
-)
+type Scope struct {
+       NoPKModel     `json:"-" mapstructure:"-"`
+       ConnectionId  uint64 `json:"connectionId" gorm:"primaryKey" 
validate:"required" mapstructure:"connectionId,omitempty"`
+       ScopeConfigId uint64 `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
+}
 
-func IsDuplicateError(err error) bool {
-       return err != nil && DUPLICATE_REGEX.MatchString(err.Error())
+// ScopeConnectionId implements plugin.ToolLayerScope.
+func (s Scope) ScopeConnectionId() uint64 {
+       return s.ConnectionId
+}
+
+func (s Scope) ScopeScopeConfigId() uint64 {
+       return s.ScopeConfigId
+}
+
+type ScopeConfig struct {
+       Model
+       Entities     []string `gorm:"type:json;serializer:json" json:"entities" 
mapstructure:"entities"`
+       ConnectionId uint64   `json:"connectionId" gorm:"index" 
validate:"required" mapstructure:"connectionId,omitempty"`
+       Name         string   `mapstructure:"name" json:"name" 
gorm:"type:varchar(255)" validate:"required"`
+}
+
+func (s ScopeConfig) ScopeConfigConnectionId() uint64 {
+       return s.ConnectionId
+}
+func (s ScopeConfig) ScopeConfigId() uint64 {
+       return s.ID
 }
diff --git a/backend/core/plugin/plugin_connection_abstract.go 
b/backend/core/plugin/plugin_datasource.go
similarity index 70%
rename from backend/core/plugin/plugin_connection_abstract.go
rename to backend/core/plugin/plugin_datasource.go
index 098dfb1fc..fa0cb8768 100644
--- a/backend/core/plugin/plugin_connection_abstract.go
+++ b/backend/core/plugin/plugin_datasource.go
@@ -18,8 +18,13 @@ limitations under the License.
 package plugin
 
 import (
+       "encoding/json"
+       "fmt"
+
        "net/http"
 
+       "github.com/apache/incubator-devlake/core/dal"
+
        "github.com/apache/incubator-devlake/core/errors"
        
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
        "github.com/go-playground/validator/v10"
@@ -44,6 +49,7 @@ type ApiAuthenticator interface {
        SetupAuthentication(request *http.Request) errors.Error
 }
 
+// TODO: deprecated, remove
 // ConnectionValidator represents the API Connection would validate its fields 
with customized logic
 type ConnectionValidator interface {
        ValidateConnection(connection interface{}, valdator 
*validator.Validate) errors.Error
@@ -87,3 +93,52 @@ type AccessTokenAuthenticator interface {
 type AppKeyAuthenticator interface {
        GetAppKeyAuthenticator() ApiAuthenticator
 }
+
+// Scope represents the top level entity for a data source, i.e. github repo,
+// gitlab project, jira board. They turn into repo, board in Domain Layer. In
+// Apache Devlake, a Project is essentially a set of these top level entities,
+// for the framework to maintain these relationships dynamically and
+// automatically, all Domain Layer Top Level Entities should implement this
+// interface
+type Scope interface {
+       ScopeId() string
+       ScopeName() string
+       TableName() string
+}
+
+type ToolLayerConnection interface {
+       dal.Tabler
+       ConnectionId() uint64
+}
+
+type ToolLayerScope interface {
+       dal.Tabler
+       Scope
+       ScopeFullName() string
+       ScopeParams() interface{}
+       ScopeConnectionId() uint64
+       ScopeScopeConfigId() uint64
+}
+
+type ToolLayerScopeConfig interface {
+       dal.Tabler
+       ScopeConfigId() uint64
+       ScopeConfigConnectionId() uint64
+}
+
+type ApiScope interface {
+       ConvertApiScope() ToolLayerScope
+}
+
+type ApiGroup interface {
+       GroupId() string
+       GroupName() string
+}
+
+func MarshalScopeParams(params interface{}) string {
+       bytes, err := json.Marshal(params)
+       if err != nil {
+               panic(fmt.Errorf("Failed to marshal %v, due to: %v", params, 
err))
+       }
+       return string(bytes)
+}
diff --git a/backend/core/plugin/plugin_scope_abstract.go 
b/backend/core/plugin/plugin_scope_abstract.go
deleted file mode 100644
index fe48ae031..000000000
--- a/backend/core/plugin/plugin_scope_abstract.go
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-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 plugin
-
-import (
-       "encoding/json"
-       "fmt"
-)
-
-// Scope represents the top level entity for a data source, i.e. github repo,
-// gitlab project, jira board. They turn into repo, board in Domain Layer. In
-// Apache Devlake, a Project is essentially a set of these top level entities,
-// for the framework to maintain these relationships dynamically and
-// automatically, all Domain Layer Top Level Entities should implement this
-// interface
-type Scope interface {
-       ScopeId() string
-       ScopeName() string
-       TableName() string
-}
-
-type ToolLayerScope interface {
-       Scope
-       ScopeFullName() string
-       ScopeParams() interface{}
-}
-
-type ApiScope interface {
-       ConvertApiScope() ToolLayerScope
-}
-
-type ApiGroup interface {
-       GroupId() string
-       GroupName() string
-}
-
-func MarshalScopeParams(params interface{}) string {
-       bytes, err := json.Marshal(params)
-       if err != nil {
-               panic(fmt.Errorf("Failed to marshal %v, due to: %v", params, 
err))
-       }
-       return string(bytes)
-}
diff --git a/backend/helpers/pluginhelper/api/connection.go 
b/backend/helpers/pluginhelper/api/connection.go
index a4877d14e..296597224 100644
--- a/backend/helpers/pluginhelper/api/connection.go
+++ b/backend/helpers/pluginhelper/api/connection.go
@@ -30,6 +30,10 @@ type BaseConnection struct {
        common.Model
 }
 
+func (c BaseConnection) ConnectionId() uint64 {
+       return c.ID
+}
+
 func (c BaseConnection) GetHash() string {
        return fmt.Sprintf("%d%v", c.ID, c.UpdatedAt)
 }
diff --git a/backend/helpers/pluginhelper/api/scope_helper_test.go 
b/backend/helpers/pluginhelper/api/scope_helper_test.go
index c994531bb..ca69688cd 100644
--- a/backend/helpers/pluginhelper/api/scope_helper_test.go
+++ b/backend/helpers/pluginhelper/api/scope_helper_test.go
@@ -41,11 +41,10 @@ type TestModel struct {
 }
 
 type TestFakeGitlabRepo struct {
-       ConnectionId     uint64     `json:"connectionId" 
mapstructure:"connectionId" gorm:"primaryKey"`
-       GitlabId         int        `json:"gitlabId" mapstructure:"gitlabId" 
gorm:"primaryKey"`
-       CreatedDate      *time.Time `json:"createdDate" mapstructure:"-"`
-       UpdatedDate      *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.Scope
+       GitlabId    int        `json:"gitlabId" mapstructure:"gitlabId" 
gorm:"primaryKey"`
+       CreatedDate *time.Time `json:"createdDate" mapstructure:"-"`
+       UpdatedDate *time.Time `json:"updatedDate" mapstructure:"-"`
 }
 
 func (t TestFakeGitlabRepo) ScopeId() string {
@@ -68,21 +67,23 @@ func (t TestFakeGitlabRepo) ScopeParams() interface{} {
        return nil
 }
 
+func (t TestFakeGitlabRepo) ScopeConnectionId() uint64 {
+       return 0
+}
+
 type TestFakeGithubRepo struct {
-       ConnectionId     uint64     `json:"connectionId" gorm:"primaryKey" 
mapstructure:"connectionId,omitempty"`
-       GithubId         int        `json:"githubId" gorm:"primaryKey" 
mapstructure:"githubId"`
-       Name             string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
-       HTMLUrl          string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
-       Description      string     `json:"description" 
mapstructure:"description,omitempty"`
-       ScopeConfigId    uint64     `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
-       OwnerId          int        `json:"ownerId" 
mapstructure:"ownerId,omitempty"`
-       Language         string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
-       ParentGithubId   int        `json:"parentId" 
mapstructure:"parentGithubId,omitempty"`
-       ParentHTMLUrl    string     `json:"parentHtmlUrl" 
mapstructure:"parentHtmlUrl,omitempty"`
-       CloneUrl         string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
-       CreatedDate      *time.Time `json:"createdDate" mapstructure:"-"`
-       UpdatedDate      *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.Scope
+       GithubId       int        `json:"githubId" gorm:"primaryKey" 
mapstructure:"githubId"`
+       Name           string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
+       HTMLUrl        string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
+       Description    string     `json:"description" 
mapstructure:"description,omitempty"`
+       OwnerId        int        `json:"ownerId" 
mapstructure:"ownerId,omitempty"`
+       Language       string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
+       ParentGithubId int        `json:"parentId" 
mapstructure:"parentGithubId,omitempty"`
+       ParentHTMLUrl  string     `json:"parentHtmlUrl" 
mapstructure:"parentHtmlUrl,omitempty"`
+       CloneUrl       string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
+       CreatedDate    *time.Time `json:"createdDate" mapstructure:"-"`
+       UpdatedDate    *time.Time `json:"updatedDate" mapstructure:"-"`
 }
 
 func (r TestFakeGithubRepo) ScopeId() string {
@@ -101,6 +102,10 @@ func (r TestFakeGithubRepo) ScopeParams() interface{} {
        return nil
 }
 
+func (TestFakeGithubRepo) ScopeConnectionId() uint64 {
+       return 0
+}
+
 func (TestFakeGithubRepo) TableName() string {
        return "_tool_github_repos"
 }
diff --git a/backend/plugins/bamboo/api/blueprint_V200_test.go 
b/backend/plugins/bamboo/api/blueprint_V200_test.go
index bd3d1abe3..da8baeba8 100644
--- a/backend/plugins/bamboo/api/blueprint_V200_test.go
+++ b/backend/plugins/bamboo/api/blueprint_V200_test.go
@@ -55,12 +55,13 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
        }
 
        var testBambooPlan = &models.BambooPlan{
-               ConnectionId: testConnectionID,
-               PlanKey:      testKey,
-               Name:         testName,
-               Href:         testLink,
-
-               ScopeConfigId: testScopeConfigId,
+               Scope: common.Scope{
+                       ConnectionId:  testConnectionID,
+                       ScopeConfigId: testScopeConfigId,
+               },
+               PlanKey: testKey,
+               Name:    testName,
+               Href:    testLink,
        }
 
        var testScopeConfig = &models.BambooScopeConfig{
diff --git a/backend/plugins/bamboo/models/plan.go 
b/backend/plugins/bamboo/models/plan.go
index 76e892fb1..d547109fc 100644
--- a/backend/plugins/bamboo/models/plan.go
+++ b/backend/plugins/bamboo/models/plan.go
@@ -26,7 +26,7 @@ var _ plugin.ToolLayerScope = (*BambooPlan)(nil)
 var _ plugin.ApiScope = (*ApiBambooPlan)(nil)
 
 type BambooPlan struct {
-       ConnectionId              uint64  `json:"connectionId" 
mapstructure:"connectionId" gorm:"primaryKey"`
+       common.Scope
        PlanKey                   string  `json:"planKey" 
mapstructure:"planKey" gorm:"primaryKey"`
        Name                      string  `json:"name" mapstructure:"name"`
        Expand                    string  `json:"expand" mapstructure:"expand"`
@@ -44,8 +44,6 @@ type BambooPlan struct {
        IsActive                  bool    `json:"isActive" 
mapstructure:"isActive"`
        IsBuilding                bool    `json:"isBuilding" 
mapstructure:"isBuilding"`
        AverageBuildTimeInSeconds float64 `json:"averageBuildTimeInSeconds" 
mapstructure:"averageBuildTimeInSeconds"`
-       ScopeConfigId             uint64  `json:"scopeConfigId" 
mapstructure:"scopeConfigId"`
-       common.NoPKModel          `json:"-" mapstructure:"-"`
 }
 
 func (p BambooPlan) ScopeId() string {
diff --git a/backend/plugins/bitbucket/api/blueprint_V200_test.go 
b/backend/plugins/bitbucket/api/blueprint_V200_test.go
index eb9d3534f..93b08bb29 100644
--- a/backend/plugins/bitbucket/api/blueprint_V200_test.go
+++ b/backend/plugins/bitbucket/api/blueprint_V200_test.go
@@ -133,11 +133,13 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 func mockBasicRes(t *testing.T) {
        testBitbucketRepo := &models.BitbucketRepo{
-               ConnectionId:  1,
-               BitbucketId:   "likyh/likyhphp",
-               Name:          "test/testRepo",
-               CloneUrl:      "https://this_is_cloneUrl";,
-               ScopeConfigId: 1,
+               Scope: common.Scope{
+                       ConnectionId:  1,
+                       ScopeConfigId: 1,
+               },
+               BitbucketId: "likyh/likyhphp",
+               Name:        "test/testRepo",
+               CloneUrl:    "https://this_is_cloneUrl";,
        }
 
        testScopeConfig := &models.BitbucketScopeConfig{
diff --git a/backend/plugins/bitbucket/models/repo.go 
b/backend/plugins/bitbucket/models/repo.go
index b6f099c02..7d88afbea 100644
--- a/backend/plugins/bitbucket/models/repo.go
+++ b/backend/plugins/bitbucket/models/repo.go
@@ -29,18 +29,16 @@ var _ plugin.ApiGroup = (*GroupResponse)(nil)
 var _ plugin.ApiScope = (*BitbucketApiRepo)(nil)
 
 type BitbucketRepo struct {
-       ConnectionId     uint64     `json:"connectionId" gorm:"primaryKey" 
validate:"required" mapstructure:"connectionId,omitempty"`
-       BitbucketId      string     `json:"bitbucketId" 
gorm:"primaryKey;type:varchar(255)" validate:"required" 
mapstructure:"bitbucketId"`
-       Name             string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
-       HTMLUrl          string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
-       Description      string     `json:"description" 
mapstructure:"description,omitempty"`
-       ScopeConfigId    uint64     `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
-       Owner            string     `json:"owner" 
mapstructure:"owner,omitempty"`
-       Language         string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
-       CloneUrl         string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
-       CreatedDate      *time.Time `json:"createdDate" mapstructure:"-"`
-       UpdatedDate      *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.Scope
+       BitbucketId string     `json:"bitbucketId" 
gorm:"primaryKey;type:varchar(255)" validate:"required" 
mapstructure:"bitbucketId"`
+       Name        string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
+       HTMLUrl     string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
+       Description string     `json:"description" 
mapstructure:"description,omitempty"`
+       Owner       string     `json:"owner" mapstructure:"owner,omitempty"`
+       Language    string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
+       CloneUrl    string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
+       CreatedDate *time.Time `json:"createdDate" mapstructure:"-"`
+       UpdatedDate *time.Time `json:"updatedDate" mapstructure:"-"`
 }
 
 func (BitbucketRepo) TableName() string {
diff --git a/backend/plugins/circleci/models/project.go 
b/backend/plugins/circleci/models/project.go
index 0c1a8024f..ee18c004f 100644
--- a/backend/plugins/circleci/models/project.go
+++ b/backend/plugins/circleci/models/project.go
@@ -23,15 +23,12 @@ import (
 )
 
 type CircleciProject struct {
-       ConnectionId   uint64 `gorm:"primaryKey;type:BIGINT" 
json:"connectionId" mapstructure:"connectionId"`
+       common.Scope
        Id             string `gorm:"primaryKey;type:varchar(100)" json:"id" 
mapstructure:"id"`
        Slug           string `gorm:"type:varchar(255)" json:"slug" 
mapstructure:"slug"`
        Name           string `gorm:"type:varchar(255)" json:"name" 
mapstructure:"name"`
        OrganizationId string `gorm:"type:varchar(100)" json:"organizationId" 
mapstructure:"organizationId"`
        // VcsInfo        CircleciVcsInfo `gorm:"serializer:json;type:text" 
json:"vcsInfo" mapstructure:"vcsInfo"`
-       ScopeConfigId uint64 `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
-
-       common.NoPKModel `swaggerignore:"true" json:"-" mapstructure:"-"`
 }
 
 type CircleciVcsInfo struct {
diff --git a/backend/plugins/gitee/models/migrationscripts/register.go 
b/backend/plugins/gitee/models/migrationscripts/20230922_add_scope_config_id.go
similarity index 50%
copy from backend/plugins/gitee/models/migrationscripts/register.go
copy to 
backend/plugins/gitee/models/migrationscripts/20230922_add_scope_config_id.go
index cbb21d711..14bc9ff12 100644
--- a/backend/plugins/gitee/models/migrationscripts/register.go
+++ 
b/backend/plugins/gitee/models/migrationscripts/20230922_add_scope_config_id.go
@@ -18,13 +18,36 @@ 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"
 )
 
-// All return all the migration scripts
-func All() []plugin.MigrationScript {
-       return []plugin.MigrationScript{
-               new(addInitTables),
-               new(addGiteeCommitAuthorInfo),
-       }
+var _ plugin.MigrationScript = (*addScopeConfigIdToRepo)(nil)
+
+type giteeRepo20230922 struct {
+       ScopeConfigId uint64 `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
+}
+
+func (giteeRepo20230922) TableName() string {
+       return "_raw_gitee_api_repo"
+}
+
+type addScopeConfigIdToRepo struct{}
+
+func (script *addScopeConfigIdToRepo) Up(basicRes context.BasicRes) 
errors.Error {
+
+       return migrationhelper.AutoMigrateTables(
+               basicRes,
+               &giteeRepo20230922{},
+       )
+}
+
+func (*addScopeConfigIdToRepo) Version() uint64 {
+       return 20230922152829
+}
+
+func (*addScopeConfigIdToRepo) Name() string {
+       return "add scope_config_id to _tool_gitee_repos table"
 }
diff --git a/backend/plugins/gitee/models/migrationscripts/register.go 
b/backend/plugins/gitee/models/migrationscripts/register.go
index cbb21d711..5e5ec1388 100644
--- a/backend/plugins/gitee/models/migrationscripts/register.go
+++ b/backend/plugins/gitee/models/migrationscripts/register.go
@@ -26,5 +26,6 @@ func All() []plugin.MigrationScript {
        return []plugin.MigrationScript{
                new(addInitTables),
                new(addGiteeCommitAuthorInfo),
+               new(addScopeConfigIdToRepo),
        }
 }
diff --git a/backend/plugins/gitee/models/repo.go 
b/backend/plugins/gitee/models/repo.go
index 9faf96769..e1f93b2f9 100644
--- a/backend/plugins/gitee/models/repo.go
+++ b/backend/plugins/gitee/models/repo.go
@@ -29,7 +29,7 @@ import (
 var _ plugin.ToolLayerScope = (*GiteeRepo)(nil)
 
 type GiteeRepo struct {
-       ConnectionId  uint64 `gorm:"primaryKey"`
+       common.Scope
        GiteeId       int    `gorm:"primaryKey"`
        Name          string `gorm:"type:varchar(255)"`
        HTMLUrl       string `gorm:"type:varchar(255)"`
@@ -41,7 +41,6 @@ type GiteeRepo struct {
        ParentHTMLUrl string     `json:"parentHtmlUrl"`
        CreatedDate   time.Time  `json:"createdDate"`
        UpdatedDate   *time.Time `json:"updatedDate"`
-       common.NoPKModel
 }
 
 func (r GiteeRepo) ScopeId() string {
diff --git a/backend/plugins/gitee/tasks/repo_extractor.go 
b/backend/plugins/gitee/tasks/repo_extractor.go
index 810e724f6..df8869c99 100644
--- a/backend/plugins/gitee/tasks/repo_extractor.go
+++ b/backend/plugins/gitee/tasks/repo_extractor.go
@@ -63,16 +63,18 @@ func ExtractApiRepositories(taskCtx plugin.SubTaskContext) 
errors.Error {
                        }
                        results := make([]interface{}, 0, 1)
                        giteeRepository := &models.GiteeRepo{
-                               ConnectionId: data.Options.ConnectionId,
-                               GiteeId:      repo.GiteeId,
-                               Name:         repo.Name,
-                               HTMLUrl:      repo.HTMLUrl,
-                               Description:  repo.Description,
-                               OwnerId:      repo.Owner.Id,
-                               OwnerLogin:   repo.Owner.Login,
-                               Language:     repo.Language,
-                               CreatedDate:  repo.CreatedAt.ToTime(),
-                               UpdatedDate:  
common.Iso8601TimeToTime(repo.UpdatedAt),
+                               Scope: common.Scope{
+                                       ConnectionId: data.Options.ConnectionId,
+                               },
+                               GiteeId:     repo.GiteeId,
+                               Name:        repo.Name,
+                               HTMLUrl:     repo.HTMLUrl,
+                               Description: repo.Description,
+                               OwnerId:     repo.Owner.Id,
+                               OwnerLogin:  repo.Owner.Login,
+                               Language:    repo.Language,
+                               CreatedDate: repo.CreatedAt.ToTime(),
+                               UpdatedDate: 
common.Iso8601TimeToTime(repo.UpdatedAt),
                        }
                        data.Repo = giteeRepository
 
diff --git a/backend/plugins/github/api/blueprint_V200_test.go 
b/backend/plugins/github/api/blueprint_V200_test.go
index 96c4c5ce0..9d3ab4ee0 100644
--- a/backend/plugins/github/api/blueprint_V200_test.go
+++ b/backend/plugins/github/api/blueprint_V200_test.go
@@ -20,6 +20,7 @@ package api
 import (
        "testing"
 
+       "github.com/apache/incubator-devlake/core/dal"
        coreModels "github.com/apache/incubator-devlake/core/models"
        "github.com/apache/incubator-devlake/core/models/common"
        "github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -29,6 +30,7 @@ import (
        helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/helpers/unithelper"
        mockdal "github.com/apache/incubator-devlake/mocks/core/dal"
+       mocks "github.com/apache/incubator-devlake/mocks/core/dal"
        mockplugin "github.com/apache/incubator-devlake/mocks/core/plugin"
        "github.com/apache/incubator-devlake/plugins/github/models"
        "github.com/stretchr/testify/assert"
@@ -135,12 +137,14 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 func mockBasicRes(t *testing.T) {
        testGithubRepo := &models.GithubRepo{
-               ConnectionId:  1,
-               GithubId:      12345,
-               Name:          "testRepo",
-               FullName:      "test/testRepo",
-               CloneUrl:      "https://this_is_cloneUrl";,
-               ScopeConfigId: 1,
+               Scope: common.Scope{
+                       ConnectionId:  1,
+                       ScopeConfigId: 1,
+               },
+               GithubId: 12345,
+               Name:     "testRepo",
+               FullName: "test/testRepo",
+               CloneUrl: "https://this_is_cloneUrl";,
        }
 
        testScopeConfig := &models.GithubScopeConfig{
@@ -169,6 +173,20 @@ func mockBasicRes(t *testing.T) {
                        dst := args.Get(0).(*models.GithubScopeConfig)
                        *dst = *testScopeConfig
                }).Return(nil)
+
+               id := new(mocks.ColumnMeta)
+               id.On("PrimayKey").Return(true)
+               id.On("Name").Return("id")
+               connectionId := new(mocks.ColumnMeta)
+               connectionId.On("PrimayKey").Return(true)
+               connectionId.On("Name").Return("connection_id")
+               githubId := new(mocks.ColumnMeta)
+               githubId.On("PrimayKey").Return(true)
+               githubId.On("Name").Return("github_id")
+
+               mockDal.On("GetColumns", 
mock.AnythingOfType("GithubConnection"), 
mock.Anything).Return([]dal.ColumnMeta{id}, nil)
+               mockDal.On("GetColumns", mock.AnythingOfType("GithubRepo"), 
mock.Anything).Return([]dal.ColumnMeta{connectionId, githubId}, nil)
+               mockDal.On("GetColumns", 
mock.AnythingOfType("GithubScopeConfig"), 
mock.Anything).Return([]dal.ColumnMeta{id}, nil)
        })
        p := mockplugin.NewPluginMeta(t)
        p.On("Name").Return("dummy").Maybe()
diff --git a/backend/plugins/github/models/repo.go 
b/backend/plugins/github/models/repo.go
index f59b44b9e..98572ca15 100644
--- a/backend/plugins/github/models/repo.go
+++ b/backend/plugins/github/models/repo.go
@@ -28,21 +28,19 @@ import (
 var _ plugin.ToolLayerScope = (*GithubRepo)(nil)
 
 type GithubRepo struct {
-       ConnectionId     uint64     `json:"connectionId" gorm:"primaryKey" 
validate:"required" mapstructure:"connectionId,omitempty"`
-       GithubId         int        `json:"githubId" gorm:"primaryKey" 
validate:"required" mapstructure:"githubId"`
-       Name             string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
-       FullName         string     `json:"fullName" gorm:"type:varchar(255)" 
mapstructure:"fullName,omitempty"`
-       HTMLUrl          string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
-       Description      string     `json:"description" 
mapstructure:"description,omitempty"`
-       ScopeConfigId    uint64     `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId,omitempty"`
-       OwnerId          int        `json:"ownerId" 
mapstructure:"ownerId,omitempty"`
-       Language         string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
-       ParentGithubId   int        `json:"parentId" 
mapstructure:"parentGithubId,omitempty"`
-       ParentHTMLUrl    string     `json:"parentHtmlUrl" 
mapstructure:"parentHtmlUrl,omitempty"`
-       CloneUrl         string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
-       CreatedDate      *time.Time `json:"createdDate" mapstructure:"-"`
-       UpdatedDate      *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.Scope   `mapstructure:",squash" gorm:"embedded"`
+       GithubId       int        `json:"githubId" gorm:"primaryKey" 
validate:"required" mapstructure:"githubId"`
+       Name           string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
+       FullName       string     `json:"fullName" gorm:"type:varchar(255)" 
mapstructure:"fullName,omitempty"`
+       HTMLUrl        string     `json:"HTMLUrl" gorm:"type:varchar(255)" 
mapstructure:"HTMLUrl,omitempty"`
+       Description    string     `json:"description" 
mapstructure:"description,omitempty"`
+       OwnerId        int        `json:"ownerId" 
mapstructure:"ownerId,omitempty"`
+       Language       string     `json:"language" gorm:"type:varchar(255)" 
mapstructure:"language,omitempty"`
+       ParentGithubId int        `json:"parentId" 
mapstructure:"parentGithubId,omitempty"`
+       ParentHTMLUrl  string     `json:"parentHtmlUrl" 
mapstructure:"parentHtmlUrl,omitempty"`
+       CloneUrl       string     `json:"cloneUrl" gorm:"type:varchar(255)" 
mapstructure:"cloneUrl,omitempty"`
+       CreatedDate    *time.Time `json:"createdDate" 
mapstructure:"createdDate"`
+       UpdatedDate    *time.Time `json:"updatedDate" 
mapstructure:"updatedDate"`
 }
 
 func (r GithubRepo) ScopeId() string {
diff --git a/backend/plugins/github/models/scope_config.go 
b/backend/plugins/github/models/scope_config.go
index 7abaf831f..625b094e1 100644
--- a/backend/plugins/github/models/scope_config.go
+++ b/backend/plugins/github/models/scope_config.go
@@ -19,12 +19,14 @@ package models
 
 import (
        "github.com/apache/incubator-devlake/core/models/common"
+       "github.com/apache/incubator-devlake/core/plugin"
        "gorm.io/datatypes"
 )
 
+var _ plugin.ToolLayerScopeConfig = (*GithubScopeConfig)(nil)
+
 type GithubScopeConfig struct {
        common.ScopeConfig   `mapstructure:",squash" json:",inline" 
gorm:"embedded"`
-       ConnectionId         uint64            `mapstructure:"connectionId" 
json:"connectionId"`
        Name                 string            `mapstructure:"name" json:"name" 
gorm:"type:varchar(255);index:idx_name_github,unique" validate:"required"`
        PrType               string            `mapstructure:"prType,omitempty" 
json:"prType" gorm:"type:varchar(255)"`
        PrComponent          string            
`mapstructure:"prComponent,omitempty" json:"prComponent" 
gorm:"type:varchar(255)"`
@@ -40,6 +42,11 @@ type GithubScopeConfig struct {
        Refdiff              datatypes.JSONMap 
`mapstructure:"refdiff,omitempty" json:"refdiff" swaggertype:"object" 
format:"json"`
 }
 
+// GetConnectionId implements plugin.ToolLayerScopeConfig.
+func (sc GithubScopeConfig) GetConnectionId() uint64 {
+       return sc.ConnectionId
+}
+
 func (GithubScopeConfig) TableName() string {
        return "_tool_github_scope_configs"
 }
diff --git a/backend/plugins/gitlab/api/blueprint_V200_test.go 
b/backend/plugins/gitlab/api/blueprint_V200_test.go
index aa366b73b..410d08572 100644
--- a/backend/plugins/gitlab/api/blueprint_V200_test.go
+++ b/backend/plugins/gitlab/api/blueprint_V200_test.go
@@ -59,11 +59,13 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
        }
 
        var testGitlabProject = &models.GitlabProject{
-               ConnectionId:      testConnectionID,
+               Scope: common.Scope{
+                       ConnectionId:  testConnectionID,
+                       ScopeConfigId: testScopeConfigId,
+               },
                GitlabId:          testID,
                Name:              testName,
                PathWithNamespace: pathWithNamespace,
-               ScopeConfigId:     testScopeConfigId,
                CreatedDate:       &time.Time{},
                HttpUrlToRepo:     testHttpUrlToRepo,
        }
diff --git a/backend/plugins/gitlab/models/project.go 
b/backend/plugins/gitlab/models/project.go
index 6770de77e..5ea5d0f62 100644
--- a/backend/plugins/gitlab/models/project.go
+++ b/backend/plugins/gitlab/models/project.go
@@ -29,8 +29,7 @@ import (
 var _ plugin.ToolLayerScope = (*GitlabProject)(nil)
 
 type GitlabProject struct {
-       ConnectionId            uint64     `json:"connectionId" 
mapstructure:"connectionId" validate:"required" gorm:"primaryKey"`
-       ScopeConfigId           uint64     `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId"`
+       common.Scope
        GitlabId                int        `json:"gitlabId" 
mapstructure:"gitlabId" validate:"required" gorm:"primaryKey"`
        Name                    string     `json:"name" mapstructure:"name" 
gorm:"type:varchar(255)"`
        Description             string     `json:"description" 
mapstructure:"description"`
@@ -47,8 +46,6 @@ type GitlabProject struct {
        CreatedDate             *time.Time `json:"createdDate" mapstructure:"-"`
        UpdatedDate             *time.Time `json:"updatedDate" mapstructure:"-"`
        Archived                bool       `json:"archived" 
mapstructure:"archived"`
-
-       common.NoPKModel `json:"-" mapstructure:"-"`
 }
 
 func (GitlabProject) TableName() string {
diff --git a/backend/plugins/jenkins/api/blueprint_v200_test.go 
b/backend/plugins/jenkins/api/blueprint_v200_test.go
index 561cc6c56..e41a30ddf 100644
--- a/backend/plugins/jenkins/api/blueprint_v200_test.go
+++ b/backend/plugins/jenkins/api/blueprint_v200_test.go
@@ -82,8 +82,10 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 func mockBasicRes(t *testing.T) {
        jenkinsJob := &models.JenkinsJob{
-               ConnectionId: 1,
-               FullName:     "a/b/ccc",
+               Scope: common.Scope{
+                       ConnectionId: 1,
+               },
+               FullName: "a/b/ccc",
        }
 
        scopeConfig := &models.JenkinsScopeConfig{
diff --git a/backend/plugins/jenkins/models/job.go 
b/backend/plugins/jenkins/models/job.go
index 16d66c782..e448dc34a 100644
--- a/backend/plugins/jenkins/models/job.go
+++ b/backend/plugins/jenkins/models/job.go
@@ -26,18 +26,16 @@ var _ plugin.ToolLayerScope = (*JenkinsJob)(nil)
 
 // 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:"-"`
+       common.Scope
+       FullName    string `gorm:"primaryKey;type:varchar(255)" 
mapstructure:"jobFullName" validate:"required" json:"jobFullName"` // 
"path1/path2/job name"
+       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"`
 }
 
 func (JenkinsJob) TableName() string {
diff --git a/backend/plugins/jira/api/blueprint_v200_test.go 
b/backend/plugins/jira/api/blueprint_v200_test.go
index 81c44186b..c03b932b5 100644
--- a/backend/plugins/jira/api/blueprint_v200_test.go
+++ b/backend/plugins/jira/api/blueprint_v200_test.go
@@ -81,9 +81,11 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 func mockBasicRes(t *testing.T) {
        jiraBoard := &models.JiraBoard{
-               ConnectionId: 1,
-               BoardId:      10,
-               Name:         "a",
+               Scope: common.Scope{
+                       ConnectionId: 1,
+               },
+               BoardId: 10,
+               Name:    "a",
        }
        scopeConfig := &models.JiraScopeConfig{
                ScopeConfig: common.ScopeConfig{
diff --git a/backend/plugins/jira/models/board.go 
b/backend/plugins/jira/models/board.go
index 4509693d7..e0e3d15f1 100644
--- a/backend/plugins/jira/models/board.go
+++ b/backend/plugins/jira/models/board.go
@@ -27,14 +27,12 @@ import (
 var _ plugin.ToolLayerScope = (*JiraBoard)(nil)
 
 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.Scope
+       BoardId   uint64 `json:"boardId" mapstructure:"boardId" 
validate:"required" gorm:"primaryKey"`
+       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 (b JiraBoard) ScopeId() string {
diff --git a/backend/plugins/pagerduty/e2e/incident_test.go 
b/backend/plugins/pagerduty/e2e/incident_test.go
index 210954f26..fe8762437 100644
--- a/backend/plugins/pagerduty/e2e/incident_test.go
+++ b/backend/plugins/pagerduty/e2e/incident_test.go
@@ -47,10 +47,12 @@ func TestIncidentDataFlow(t *testing.T) {
        dataflowTester.FlushTabler(&models.Service{})
        // tx-rule
        service := models.Service{
-               ConnectionId: options.ConnectionId,
-               Url:          
fmt.Sprintf("https://keon-test.pagerduty.com/service-directory/%s";, 
options.ServiceId),
-               Id:           options.ServiceId,
-               Name:         options.ServiceName,
+               Scope: common.Scope{
+                       ConnectionId: options.ConnectionId,
+               },
+               Url:  
fmt.Sprintf("https://keon-test.pagerduty.com/service-directory/%s";, 
options.ServiceId),
+               Id:   options.ServiceId,
+               Name: options.ServiceName,
        }
        // scope
        require.NoError(t, dataflowTester.Dal.CreateOrUpdate(&service))
diff --git a/backend/plugins/pagerduty/models/scope_config.go 
b/backend/plugins/pagerduty/models/scope_config.go
index cda12a4c5..3f3450e44 100644
--- a/backend/plugins/pagerduty/models/scope_config.go
+++ b/backend/plugins/pagerduty/models/scope_config.go
@@ -23,6 +23,4 @@ import (
 
 type PagerdutyScopeConfig struct {
        common.ScopeConfig `mapstructure:",squash" json:",inline" 
gorm:"embedded"`
-       Name               string `mapstructure:"name" json:"name" 
gorm:"type:varchar(255);index:idx_name_github,unique" validate:"required"`
-       ConnectionId       uint64
 }
diff --git a/backend/plugins/pagerduty/models/service.go 
b/backend/plugins/pagerduty/models/service.go
index 7bda04260..365aec200 100644
--- a/backend/plugins/pagerduty/models/service.go
+++ b/backend/plugins/pagerduty/models/service.go
@@ -28,11 +28,10 @@ type PagerDutyParams struct {
 }
 
 type Service struct {
-       common.NoPKModel
-       ConnectionId uint64 `json:"connection_id" 
mapstructure:"connectionId,omitempty" gorm:"primaryKey" `
-       Id           string `json:"id" mapstructure:"id" 
gorm:"primaryKey;autoIncrement:false" `
-       Url          string `json:"url" mapstructure:"url"`
-       Name         string `json:"name" mapstructure:"name"`
+       common.Scope
+       Id   string `json:"id" mapstructure:"id" 
gorm:"primaryKey;autoIncrement:false" `
+       Url  string `json:"url" mapstructure:"url"`
+       Name string `json:"name" mapstructure:"name"`
 }
 
 func (s Service) ScopeId() string {
diff --git a/backend/plugins/pagerduty/tasks/incidents_extractor.go 
b/backend/plugins/pagerduty/tasks/incidents_extractor.go
index f0e469660..755c0674e 100644
--- a/backend/plugins/pagerduty/tasks/incidents_extractor.go
+++ b/backend/plugins/pagerduty/tasks/incidents_extractor.go
@@ -19,7 +19,9 @@ package tasks
 
 import (
        "encoding/json"
+
        "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/models/common"
        "github.com/apache/incubator-devlake/core/plugin"
        "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/plugins/pagerduty/models"
@@ -56,10 +58,12 @@ func ExtractIncidents(taskCtx plugin.SubTaskContext) 
errors.Error {
                        results = append(results, &incident)
                        if incidentRaw.Service != nil {
                                service := models.Service{
-                                       ConnectionId: data.Options.ConnectionId,
-                                       Url:          
resolve(incidentRaw.Service.HtmlUrl),
-                                       Id:           *incidentRaw.Service.Id,
-                                       Name:         
*incidentRaw.Service.Summary,
+                                       Scope: common.Scope{
+                                               ConnectionId: 
data.Options.ConnectionId,
+                                       },
+                                       Url:  
resolve(incidentRaw.Service.HtmlUrl),
+                                       Id:   *incidentRaw.Service.Id,
+                                       Name: *incidentRaw.Service.Summary,
                                }
                                incident.ServiceId = service.Id
                                results = append(results, &service)
diff --git a/backend/plugins/sonarqube/api/blueprint_v200_test.go 
b/backend/plugins/sonarqube/api/blueprint_v200_test.go
index 093355e8a..365548f77 100644
--- a/backend/plugins/sonarqube/api/blueprint_v200_test.go
+++ b/backend/plugins/sonarqube/api/blueprint_v200_test.go
@@ -21,6 +21,7 @@ import (
        "testing"
 
        coreModels "github.com/apache/incubator-devlake/core/models"
+       "github.com/apache/incubator-devlake/core/models/common"
        "github.com/apache/incubator-devlake/core/models/domainlayer"
        
"github.com/apache/incubator-devlake/core/models/domainlayer/codequality"
        "github.com/apache/incubator-devlake/core/plugin"
@@ -81,9 +82,11 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 // NewMockBasicRes FIXME ...
 func NewMockBasicRes() *mockcontext.BasicRes {
        sonarqubeProject := &models.SonarqubeProject{
-               ConnectionId: 1,
-               ProjectKey:   "f5a50c63-2e8f-4107-9014-853f6f467757",
-               Name:         "aerosolve",
+               Scope: common.Scope{
+                       ConnectionId: 1,
+               },
+               ProjectKey: "f5a50c63-2e8f-4107-9014-853f6f467757",
+               Name:       "aerosolve",
        }
 
        mockRes := new(mockcontext.BasicRes)
diff --git a/backend/plugins/sonarqube/models/sonarqube_project.go 
b/backend/plugins/sonarqube/models/sonarqube_project.go
index 0f9c3dab3..c4bc92dbc 100644
--- a/backend/plugins/sonarqube/models/sonarqube_project.go
+++ b/backend/plugins/sonarqube/models/sonarqube_project.go
@@ -26,8 +26,7 @@ var _ plugin.ToolLayerScope = (*SonarqubeProject)(nil)
 var _ plugin.ApiScope = (*SonarqubeApiProject)(nil)
 
 type SonarqubeProject struct {
-       common.NoPKModel `json:"-" mapstructure:"-"`
-       ConnectionId     uint64              `json:"connectionId" 
validate:"required" gorm:"primaryKey" mapstructure:"connectionId"`
+       common.Scope
        ProjectKey       string              `json:"projectKey" 
validate:"required" gorm:"type:varchar(255);primaryKey" 
mapstructure:"projectKey"`
        Name             string              `json:"name" 
gorm:"type:varchar(255)" mapstructure:"name"`
        Qualifier        string              `json:"qualifier" 
gorm:"type:varchar(255)" mapstructure:"qualifier"`
diff --git a/backend/plugins/tapd/api/blueprint_v200_test.go 
b/backend/plugins/tapd/api/blueprint_v200_test.go
index bb3a17eec..fe15f6489 100644
--- a/backend/plugins/tapd/api/blueprint_v200_test.go
+++ b/backend/plugins/tapd/api/blueprint_v200_test.go
@@ -81,9 +81,11 @@ func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
 
 func mockBasicRes(t *testing.T) {
        tapdWorkspace := &models.TapdWorkspace{
-               ConnectionId: 1,
-               Id:           10,
-               Name:         "a",
+               Scope: common.Scope{
+                       ConnectionId: 1,
+               },
+               Id:   10,
+               Name: "a",
        }
        scopeConfig := &models.TapdScopeConfig{
                ScopeConfig: common.ScopeConfig{
diff --git a/backend/plugins/tapd/api/remote.go 
b/backend/plugins/tapd/api/remote.go
index cefa3f2ea..b11c74412 100644
--- a/backend/plugins/tapd/api/remote.go
+++ b/backend/plugins/tapd/api/remote.go
@@ -21,6 +21,10 @@ import (
        gocontext "context"
        "encoding/json"
        "fmt"
+       "io"
+       "net/http"
+       "net/url"
+
        "github.com/apache/incubator-devlake/core/context"
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"
@@ -28,9 +32,6 @@ import (
        aha 
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
        "github.com/apache/incubator-devlake/plugins/tapd/models"
        "github.com/apache/incubator-devlake/plugins/tapd/tasks"
-       "io"
-       "net/http"
-       "net/url"
 )
 
 // PrepareFirstPageToken prepare first page token
@@ -91,16 +92,16 @@ func RemoteScopes(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, er
                        // check if workspace is a group
                        isGroupMap := map[uint64]bool{}
                        for _, workspace := range resBody.Data {
-                               isGroupMap[workspace.ApiTapdWorkspace.ParentId] 
= true
+                               isGroupMap[workspace.TapdWorkspace.ParentId] = 
true
                        }
 
                        groups := []api.BaseRemoteGroupResponse{}
                        for _, workspace := range resBody.Data {
-                               if fmt.Sprintf(`%d`, 
workspace.ApiTapdWorkspace.ParentId) == gid &&
-                                       
isGroupMap[workspace.ApiTapdWorkspace.Id] {
+                               if fmt.Sprintf(`%d`, 
workspace.TapdWorkspace.ParentId) == gid &&
+                                       isGroupMap[workspace.TapdWorkspace.Id] {
                                        groups = append(groups, 
api.BaseRemoteGroupResponse{
-                                               Id:   fmt.Sprintf(`%d`, 
workspace.ApiTapdWorkspace.Id),
-                                               Name: 
workspace.ApiTapdWorkspace.Name,
+                                               Id:   fmt.Sprintf(`%d`, 
workspace.TapdWorkspace.Id),
+                                               Name: 
workspace.TapdWorkspace.Name,
                                        })
                                }
                        }
@@ -130,9 +131,9 @@ func RemoteScopes(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, er
                        }
                        workspaces := []models.TapdWorkspace{}
                        for _, workspace := range resBody.Data {
-                               if fmt.Sprintf(`%d`, 
workspace.ApiTapdWorkspace.ParentId) == gid {
+                               if fmt.Sprintf(`%d`, 
workspace.TapdWorkspace.ParentId) == gid {
                                        // filter from all project to query 
what we need...
-                                       workspaces = append(workspaces, 
models.TapdWorkspace(workspace.ApiTapdWorkspace))
+                                       workspaces = append(workspaces, 
models.TapdWorkspace(workspace.TapdWorkspace))
                                }
 
                        }
@@ -162,7 +163,7 @@ func GetApiWorkspace(op *tasks.TapdOptions, apiClient 
aha.ApiClientAbstract) (*m
        if err != nil {
                return nil, err
        }
-       workspace := models.TapdWorkspace(resBody.Data.ApiTapdWorkspace)
+       workspace := models.TapdWorkspace(resBody.Data.TapdWorkspace)
        workspace.ConnectionId = op.ConnectionId
        return &workspace, nil
 }
diff --git a/backend/plugins/tapd/models/workspace.go 
b/backend/plugins/tapd/models/workspace.go
index 40572ab01..1fd8f26c2 100644
--- a/backend/plugins/tapd/models/workspace.go
+++ b/backend/plugins/tapd/models/workspace.go
@@ -24,28 +24,10 @@ import (
        "github.com/apache/incubator-devlake/core/plugin"
 )
 
-type ApiTapdWorkspace struct {
-       ConnectionId  uint64          `gorm:"primaryKey;type:BIGINT  NOT NULL"`
-       Id            uint64          `gorm:"primaryKey;type:BIGINT NOT 
NULL;autoIncrement:false" json:"id,string"`
-       Name          string          `gorm:"type:varchar(255)" json:"name"`
-       PrettyName    string          `gorm:"type:varchar(255)" 
json:"pretty_name"`
-       Category      string          `gorm:"type:varchar(255)" json:"category"`
-       Status        string          `gorm:"type:varchar(255)" json:"status"`
-       Description   string          `json:"description"`
-       BeginDate     *common.CSTTime `json:"begin_date"`
-       EndDate       *common.CSTTime `json:"end_date"`
-       ExternalOn    string          `gorm:"type:varchar(255)" 
json:"external_on"`
-       ParentId      uint64          `gorm:"type:BIGINT" 
json:"parent_id,string"`
-       Creator       string          `gorm:"type:varchar(255)" json:"creator"`
-       Created       *common.CSTTime `json:"created"`
-       ScopeConfigId uint64          `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId"`
-       common.NoPKModel
-}
-
 type WorkspacesResponse struct {
        Status int `json:"status"`
        Data   []struct {
-               ApiTapdWorkspace `json:"Workspace"`
+               TapdWorkspace `json:"Workspace"`
        } `json:"data"`
        Info string `json:"info"`
 }
@@ -53,27 +35,25 @@ type WorkspacesResponse struct {
 type WorkspaceResponse struct {
        Status int `json:"status"`
        Data   struct {
-               ApiTapdWorkspace `json:"Workspace"`
+               TapdWorkspace `json:"Workspace"`
        } `json:"data"`
        Info string `json:"info"`
 }
 
 type TapdWorkspace struct {
-       ConnectionId     uint64          `gorm:"primaryKey;type:BIGINT  NOT 
NULL" mapstructure:"connection_id" json:"connection_id"`
-       Id               uint64          `gorm:"primaryKey;type:BIGINT" 
mapstructure:"id" json:"id"`
-       Name             string          `gorm:"type:varchar(255)" 
mapstructure:"name" json:"name"`
-       PrettyName       string          `gorm:"type:varchar(255)" 
mapstructure:"pretty_name" json:"pretty_name"`
-       Category         string          `gorm:"type:varchar(255)" 
mapstructure:"category" json:"category"`
-       Status           string          `gorm:"type:varchar(255)" 
mapstructure:"status" json:"status"`
-       Description      string          `mapstructure:"description" 
json:"description"`
-       BeginDate        *common.CSTTime `mapstructure:"begin_date" 
json:"begin_date"`
-       EndDate          *common.CSTTime `mapstructure:"end_date" 
json:"end_date"`
-       ExternalOn       string          `gorm:"type:varchar(255)" 
mapstructure:"external_on" json:"external_on"`
-       ParentId         uint64          `gorm:"type:BIGINT" 
mapstructure:"parent_id,string" json:"parent_id"`
-       Creator          string          `gorm:"type:varchar(255)" 
mapstructure:"creator" json:"creator"`
-       Created          *common.CSTTime `mapstructure:"created" json:"created"`
-       ScopeConfigId    uint64          
`mapstructure:"scopeConfigId,omitempty" json:"scopeConfigId,omitempty"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.Scope
+       Id          uint64          `gorm:"primaryKey;type:BIGINT" 
mapstructure:"id" json:"id"`
+       Name        string          `gorm:"type:varchar(255)" 
mapstructure:"name" json:"name"`
+       PrettyName  string          `gorm:"type:varchar(255)" 
mapstructure:"pretty_name" json:"pretty_name"`
+       Category    string          `gorm:"type:varchar(255)" 
mapstructure:"category" json:"category"`
+       Status      string          `gorm:"type:varchar(255)" 
mapstructure:"status" json:"status"`
+       Description string          `mapstructure:"description" 
json:"description"`
+       BeginDate   *common.CSTTime `mapstructure:"begin_date" 
json:"begin_date"`
+       EndDate     *common.CSTTime `mapstructure:"end_date" json:"end_date"`
+       ExternalOn  string          `gorm:"type:varchar(255)" 
mapstructure:"external_on" json:"external_on"`
+       ParentId    uint64          `gorm:"type:BIGINT" 
mapstructure:"parent_id,string" json:"parent_id"`
+       Creator     string          `gorm:"type:varchar(255)" 
mapstructure:"creator" json:"creator"`
+       Created     *common.CSTTime `mapstructure:"created" json:"created"`
 }
 
 func (TapdWorkspace) TableName() string {
diff --git a/backend/plugins/trello/models/board.go 
b/backend/plugins/trello/models/board.go
index d651c91e2..815746c12 100644
--- a/backend/plugins/trello/models/board.go
+++ b/backend/plugins/trello/models/board.go
@@ -25,11 +25,10 @@ import (
 var _ plugin.ToolLayerScope = (*TrelloBoard)(nil)
 
 type TrelloBoard struct {
-       common.NoPKModel `json:"-" mapstructure:"-"`
-       ConnectionId     uint64 `json:"connectionId" 
mapstructure:"connectionId" gorm:"primaryKey"`
-       BoardId          string `json:"boardId" mapstructure:"boardId" 
gorm:"type:varchar(255)"`
-       ScopeConfigId    uint64 `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId"`
-       Name             string `json:"name" mapstructure:"name" 
gorm:"type:varchar(255)"`
+       common.Scope
+       ConnectionId uint64 `json:"connectionId" mapstructure:"connectionId" 
gorm:"primaryKey"`
+       BoardId      string `json:"boardId" mapstructure:"boardId" 
gorm:"type:varchar(255)"`
+       Name         string `json:"name" mapstructure:"name" 
gorm:"type:varchar(255)"`
 }
 
 func (b TrelloBoard) ScopeId() string {
diff --git a/backend/plugins/zentao/api/blueprint_V200_test.go 
b/backend/plugins/zentao/api/blueprint_V200_test.go
index 2cd62a269..53a55690e 100644
--- a/backend/plugins/zentao/api/blueprint_V200_test.go
+++ b/backend/plugins/zentao/api/blueprint_V200_test.go
@@ -136,11 +136,13 @@ func mockBasicRes(t *testing.T) {
                ScopeConfigId: 0,
        }*/
        testZentaoProject := &models.ZentaoProject{
-               ConnectionId:  1,
-               Id:            1,
-               Name:          "test/testRepo",
-               Type:          `project`,
-               ScopeConfigId: 0,
+               Scope: common.Scope{
+                       ConnectionId:  1,
+                       ScopeConfigId: 0,
+               },
+               Id:   1,
+               Name: "test/testRepo",
+               Type: `project`,
        }
        mockRes := unithelper.DummyBasicRes(func(mockDal *mockdal.Dal) {
                mockDal.On("First", 
mock.AnythingOfType("*models.ZentaoProject"), mock.Anything).Run(func(args 
mock.Arguments) {
diff --git a/backend/plugins/zentao/models/project.go 
b/backend/plugins/zentao/models/project.go
index 427dc5244..3db2744f2 100644
--- a/backend/plugins/zentao/models/project.go
+++ b/backend/plugins/zentao/models/project.go
@@ -19,47 +19,47 @@ package models
 
 import (
        "fmt"
-       "github.com/spf13/cast"
        "strconv"
 
+       "github.com/spf13/cast"
+
        "github.com/apache/incubator-devlake/core/models/common"
        "github.com/apache/incubator-devlake/core/plugin"
 )
 
 type ZentaoProject struct {
-       common.NoPKModel `json:"-"`
-       ConnectionId     uint64              `json:"connectionid" 
mapstructure:"connectionid" gorm:"primaryKey;type:BIGINT  NOT NULL"`
-       Id               int64               `json:"id" mapstructure:"id" 
gorm:"primaryKey;type:BIGINT  NOT NULL;autoIncrement:false"`
-       Project          int64               `json:"project" 
mapstructure:"project"`
-       Model            string              `json:"model" mapstructure:"model"`
-       Type             string              `json:"type" mapstructure:"type"`
-       ProjectType      string              `json:"projectType" 
mapstructure:"projectType"`
-       Lifetime         string              `json:"lifetime" 
mapstructure:"lifetime"`
-       Budget           string              `json:"budget" 
mapstructure:"budget"`
-       BudgetUnit       string              `json:"budgetUnit" 
mapstructure:"budgetUnit"`
-       Attribute        string              `json:"attribute" 
mapstructure:"attribute"`
-       Percent          int                 `json:"percent" 
mapstructure:"percent"`
-       Milestone        string              `json:"milestone" 
mapstructure:"milestone"`
-       Output           string              `json:"output" 
mapstructure:"output"`
-       Auth             string              `json:"auth" mapstructure:"auth"`
-       Parent           int64               `json:"parent" 
mapstructure:"parent"`
-       Path             string              `json:"path" mapstructure:"path"`
-       Grade            int                 `json:"grade" mapstructure:"grade"`
-       Name             string              `json:"name" mapstructure:"name"`
-       Code             string              `json:"code" mapstructure:"code"`
-       PlanBegin        *common.Iso8601Time `json:"begin" mapstructure:"begin"`
-       PlanEnd          *common.Iso8601Time `json:"end" mapstructure:"end"`
-       RealBegan        *common.Iso8601Time `json:"realBegan" 
mapstructure:"realBegan"`
-       RealEnd          *common.Iso8601Time `json:"realEnd" 
mapstructure:"realEnd"`
-       Days             int                 `json:"days" mapstructure:"days"`
-       Status           string              `json:"status" 
mapstructure:"status"`
-       SubStatus        string              `json:"subStatus" 
mapstructure:"subStatus"`
-       Pri              string              `json:"pri" mapstructure:"pri"`
-       Description      string              `json:"desc" mapstructure:"desc"`
-       Version          int                 `json:"version" 
mapstructure:"version"`
-       ParentVersion    int                 `json:"parentVersion" 
mapstructure:"parentVersion"`
-       PlanDuration     int                 `json:"planDuration" 
mapstructure:"planDuration"`
-       RealDuration     int                 `json:"realDuration" 
mapstructure:"realDuration"`
+       common.Scope
+       Id            int64               `json:"id" mapstructure:"id" 
gorm:"primaryKey;type:BIGINT  NOT NULL;autoIncrement:false"`
+       Project       int64               `json:"project" 
mapstructure:"project"`
+       Model         string              `json:"model" mapstructure:"model"`
+       Type          string              `json:"type" mapstructure:"type"`
+       ProjectType   string              `json:"projectType" 
mapstructure:"projectType"`
+       Lifetime      string              `json:"lifetime" 
mapstructure:"lifetime"`
+       Budget        string              `json:"budget" mapstructure:"budget"`
+       BudgetUnit    string              `json:"budgetUnit" 
mapstructure:"budgetUnit"`
+       Attribute     string              `json:"attribute" 
mapstructure:"attribute"`
+       Percent       int                 `json:"percent" 
mapstructure:"percent"`
+       Milestone     string              `json:"milestone" 
mapstructure:"milestone"`
+       Output        string              `json:"output" mapstructure:"output"`
+       Auth          string              `json:"auth" mapstructure:"auth"`
+       Parent        int64               `json:"parent" mapstructure:"parent"`
+       Path          string              `json:"path" mapstructure:"path"`
+       Grade         int                 `json:"grade" mapstructure:"grade"`
+       Name          string              `json:"name" mapstructure:"name"`
+       Code          string              `json:"code" mapstructure:"code"`
+       PlanBegin     *common.Iso8601Time `json:"begin" mapstructure:"begin"`
+       PlanEnd       *common.Iso8601Time `json:"end" mapstructure:"end"`
+       RealBegan     *common.Iso8601Time `json:"realBegan" 
mapstructure:"realBegan"`
+       RealEnd       *common.Iso8601Time `json:"realEnd" 
mapstructure:"realEnd"`
+       Days          int                 `json:"days" mapstructure:"days"`
+       Status        string              `json:"status" mapstructure:"status"`
+       SubStatus     string              `json:"subStatus" 
mapstructure:"subStatus"`
+       Pri           string              `json:"pri" mapstructure:"pri"`
+       Description   string              `json:"desc" mapstructure:"desc"`
+       Version       int                 `json:"version" 
mapstructure:"version"`
+       ParentVersion int                 `json:"parentVersion" 
mapstructure:"parentVersion"`
+       PlanDuration  int                 `json:"planDuration" 
mapstructure:"planDuration"`
+       RealDuration  int                 `json:"realDuration" 
mapstructure:"realDuration"`
        //OpenedBy       string    `json:"openedBy" mapstructure:"openedBy"`
        OpenedDate    *common.Iso8601Time `json:"openedDate" 
mapstructure:"openedDate"`
        OpenedVersion string              `json:"openedVersion" 
mapstructure:"openedVersion"`
@@ -94,7 +94,6 @@ type ZentaoProject struct {
        TotalLeft     float64 `json:"totalLeft" mapstructure:"totalLeft"`
        Progress      float64
        ProgressRes   interface{} `json:"progress" mapstructure:"progress" 
gorm:"-"`
-       ScopeConfigId uint64      `json:"scopeConfigId,omitempty" 
mapstructure:"scopeConfigId"`
 }
 
 type PM struct {
diff --git a/backend/server/services/remote/models/models.go 
b/backend/server/services/remote/models/models.go
index 00621301b..58cd39ce5 100644
--- a/backend/server/services/remote/models/models.go
+++ b/backend/server/services/remote/models/models.go
@@ -79,6 +79,16 @@ type DynamicScopeModel struct {
        models.DynamicTabler
 }
 
+// ScopeScopeConfigId implements plugin.ToolLayerScope.
+func (d DynamicScopeModel) ScopeScopeConfigId() uint64 {
+       return 
reflect.ValueOf(d.DynamicTabler.Unwrap()).Elem().FieldByName("ScopeConfigId").Uint()
+}
+
+// ScopeConnectionId implements plugin.ToolLayerScope.
+func (d DynamicScopeModel) ScopeConnectionId() uint64 {
+       return d.ConnectionId()
+}
+
 func NewDynamicScopeModel(model models.DynamicTabler) *DynamicScopeModel {
        return &DynamicScopeModel{
                DynamicTabler: model.New(),

Reply via email to