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 a4ceca52a refactor: sonarqube adopts the new dshelper (#6644)
a4ceca52a is described below
commit a4ceca52a327bf1c62f672f95546ae05b1e13cf4
Author: Klesh Wong <[email protected]>
AuthorDate: Fri Dec 22 15:39:36 2023 +0800
refactor: sonarqube adopts the new dshelper (#6644)
* docs: fix connection api doc
* refactor: sonarqube adopts the new dshelper
* fix: scope config service helper should fill the enitites when omitted
* fix: typo
---
backend/helpers/pluginhelper/api/ds_helper.go | 14 +-
.../helpers/srvhelper/connection_service_helper.go | 8 +-
.../srvhelper/scope_config_service_helper.go | 7 +
backend/helpers/srvhelper/scope_service_helper.go | 24 +++-
.../helpers/srvhelper/scope_service_helper_test.go | 55 +++++++
backend/plugins/github/api/connection_api.go | 2 +-
backend/plugins/gitlab/api/connection_api.go | 2 +-
backend/plugins/jenkins/api/connection_api.go | 2 +-
backend/plugins/jira/api/connection_api.go | 2 +-
backend/plugins/sonarqube/api/blueprint_v200.go | 101 +++++++------
.../plugins/sonarqube/api/blueprint_v200_test.go | 104 --------------
.../api/{connection.go => connection_api.go} | 45 ++----
backend/plugins/sonarqube/api/init.go | 44 ++----
backend/plugins/sonarqube/api/proxy.go | 61 --------
backend/plugins/sonarqube/api/remote.go | 116 ---------------
backend/plugins/sonarqube/api/remote_api.go | 160 +++++++++++++++++++++
.../sonarqube/api/{scope.go => scope_api.go} | 31 ++--
backend/plugins/sonarqube/impl/impl.go | 3 +-
.../plugins/sonarqube/models/sonarqube_project.go | 6 +-
backend/plugins/sonarqube/tasks/task_data.go | 5 +-
backend/test/e2e/manual/gitlab/gitlab_test.go | 2 +-
21 files changed, 370 insertions(+), 424 deletions(-)
diff --git a/backend/helpers/pluginhelper/api/ds_helper.go
b/backend/helpers/pluginhelper/api/ds_helper.go
index e4e823a86..0b14356e3 100644
--- a/backend/helpers/pluginhelper/api/ds_helper.go
+++ b/backend/helpers/pluginhelper/api/ds_helper.go
@@ -18,11 +18,15 @@ limitations under the License.
package api
import (
+ "reflect"
+
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/srvhelper"
)
+var noScopeConfig = reflect.TypeOf(new(srvhelper.NoScopeConfig))
+
type DsHelper[
C plugin.ToolLayerConnection,
S plugin.ToolLayerScope,
@@ -52,8 +56,14 @@ func NewDataSourceHelper[
connApi := NewDsConnectionApiHelper[C, S, SC](basicRes, connSrv,
connectionSterilizer)
scopeSrv := srvhelper.NewScopeSrvHelper[C, S, SC](basicRes, pluginName,
scopeSearchColumns)
scopeApi := NewDsScopeApiHelper[C, S, SC](basicRes, scopeSrv,
scopeSterilizer)
- scSrv := srvhelper.NewScopeConfigSrvHelper[C, S, SC](basicRes,
scopeSearchColumns)
- scApi := NewDsScopeConfigApiHelper[C, S, SC](basicRes, scSrv,
scopeConfigSterilizer)
+
+ var scSrv *srvhelper.ScopeConfigSrvHelper[C, S, SC]
+ var scApi *DsScopeConfigApiHelper[C, S, SC]
+ scType := reflect.TypeOf(new(SC))
+ if scType != noScopeConfig {
+ scSrv = srvhelper.NewScopeConfigSrvHelper[C, S, SC](basicRes,
scopeSearchColumns)
+ scApi = NewDsScopeConfigApiHelper[C, S, SC](basicRes, scSrv,
scopeConfigSterilizer)
+ }
return &DsHelper[C, S, SC]{
ConnSrv: connSrv,
ConnApi: connApi,
diff --git a/backend/helpers/srvhelper/connection_service_helper.go
b/backend/helpers/srvhelper/connection_service_helper.go
index 9cc1dea28..7244e2724 100644
--- a/backend/helpers/srvhelper/connection_service_helper.go
+++ b/backend/helpers/srvhelper/connection_service_helper.go
@@ -18,6 +18,8 @@ limitations under the License.
package srvhelper
import (
+ "reflect"
+
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
@@ -52,14 +54,16 @@ func (connSrv *ConnectionSrvHelper[C, S, SC])
DeleteConnection(connection *C) (r
connectionId := (*connection).ConnectionId()
refs =
toDsRefs(connSrv.getAllBlueprinsByConnection(connectionId))
if refs != nil {
- return errors.Conflict.New("Cannot delete the scope
because it is referenced by blueprints")
+ return errors.Conflict.New("Cannot delete the
connection because it is referenced by blueprints")
}
scopeCount := errors.Must1(connSrv.db.Count(dal.From(new(S)),
dal.Where("connection_id = ?", connectionId)))
if scopeCount > 0 {
return errors.Conflict.New("Please delete all data
scope(s) before you delete this Data Connection.")
}
errors.Must(tx.Delete(connection))
- errors.Must(connSrv.db.Delete(new(SC), dal.Where("connection_id
= ?", connectionId)))
+ if reflect.TypeOf(new(SC)) !=
reflect.TypeOf(new(NoScopeConfig)) {
+ errors.Must(connSrv.db.Delete(new(SC),
dal.Where("connection_id = ?", connectionId)))
+ }
return nil
})
return
diff --git a/backend/helpers/srvhelper/scope_config_service_helper.go
b/backend/helpers/srvhelper/scope_config_service_helper.go
index 506c64e39..796ba29a5 100644
--- a/backend/helpers/srvhelper/scope_config_service_helper.go
+++ b/backend/helpers/srvhelper/scope_config_service_helper.go
@@ -24,6 +24,13 @@ import (
"github.com/apache/incubator-devlake/core/plugin"
)
+// NoScopeConfig is a placeholder for plugins that don't have any scope
configuration yet
+type NoScopeConfig struct{}
+
+func (NoScopeConfig) TableName() string { return "" }
+func (NoScopeConfig) ScopeConfigId() uint64 { return 0 }
+func (NoScopeConfig) ScopeConfigConnectionId() uint64 { return 0 }
+
// ScopeConfigSrvHelper
type ScopeConfigSrvHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope, SC plugin.ToolLayerScopeConfig] struct {
*ModelSrvHelper[SC]
diff --git a/backend/helpers/srvhelper/scope_service_helper.go
b/backend/helpers/srvhelper/scope_service_helper.go
index 630457e25..4235bafa3 100644
--- a/backend/helpers/srvhelper/scope_service_helper.go
+++ b/backend/helpers/srvhelper/scope_service_helper.go
@@ -19,15 +19,16 @@ package srvhelper
import (
"fmt"
+ "reflect"
+ "sort"
+ "strings"
+
"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"
"github.com/apache/incubator-devlake/core/models/domainlayer/domaininfo"
"github.com/apache/incubator-devlake/core/plugin"
- "reflect"
- "sort"
- "strings"
)
type ScopePagination struct {
@@ -132,6 +133,7 @@ func (scopeSrv *ScopeSrvHelper[C, S, SC])
MapScopeDetails(connectionId uint64, b
if scopeDetails[i].ScopeConfig == nil {
scopeDetails[i].ScopeConfig = new(SC)
}
+ setDefaultEntities(scopeDetails[i].ScopeConfig)
}
return scopeDetails, nil
}
@@ -318,3 +320,19 @@ func reflectType(obj any) reflect.Type {
}
return typ
}
+
+func setDefaultEntities(sc interface{}) {
+ v := reflect.ValueOf(sc)
+ if v.Kind() != reflect.Pointer {
+ panic(fmt.Errorf("sc must be a pointer"))
+ }
+ entities := v.Elem().FieldByName("Entities")
+ if !entities.IsValid() ||
+ !(entities.Kind() == reflect.Array || entities.Kind() ==
reflect.Slice) ||
+ entities.Type().Elem().Kind() != reflect.String {
+ return
+ }
+ if entities.IsNil() || entities.Len() == 0 {
+ entities.Set(reflect.ValueOf(plugin.DOMAIN_TYPES))
+ }
+}
diff --git a/backend/helpers/srvhelper/scope_service_helper_test.go
b/backend/helpers/srvhelper/scope_service_helper_test.go
new file mode 100644
index 000000000..1052b8164
--- /dev/null
+++ b/backend/helpers/srvhelper/scope_service_helper_test.go
@@ -0,0 +1,55 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package srvhelper
+
+import (
+ "testing"
+
+ "github.com/apache/incubator-devlake/core/models/common"
+ "github.com/apache/incubator-devlake/core/plugin"
+ "github.com/magiconair/properties/assert"
+)
+
+func Test_setDefaultEntities(t *testing.T) {
+ // plugin doesn't embed the common ScopeConfig
+ sc1 := &struct {
+ Entities []string
+ }{
+ Entities: nil,
+ }
+ setDefaultEntities(sc1)
+ assert.Equal(t, sc1.Entities, plugin.DOMAIN_TYPES)
+
+ // plugin embeded the common ScopeConfig
+ sc2 := &struct {
+ common.ScopeConfig
+ }{
+ ScopeConfig: common.ScopeConfig{
+ Entities: nil,
+ },
+ }
+ setDefaultEntities(sc2)
+ assert.Equal(t, sc2.Entities, plugin.DOMAIN_TYPES)
+
+ // should not override a non empty slice
+ sc3 := &common.ScopeConfig{
+ Entities: []string{plugin.DOMAIN_TYPE_CICD},
+ }
+ setDefaultEntities(sc3)
+ assert.Equal(t, sc3.Entities, []string{plugin.DOMAIN_TYPE_CICD})
+}
diff --git a/backend/plugins/github/api/connection_api.go
b/backend/plugins/github/api/connection_api.go
index bbee00bcf..77aa985e5 100644
--- a/backend/plugins/github/api/connection_api.go
+++ b/backend/plugins/github/api/connection_api.go
@@ -112,7 +112,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Tags plugins/github
// @Success 200 {object} models.GithubConnection
// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this
connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/github/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
diff --git a/backend/plugins/gitlab/api/connection_api.go
b/backend/plugins/gitlab/api/connection_api.go
index c03cf1727..e70151bf5 100644
--- a/backend/plugins/gitlab/api/connection_api.go
+++ b/backend/plugins/gitlab/api/connection_api.go
@@ -145,7 +145,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Tags plugins/gitlab
// @Success 200 {object} models.GitlabConnection
// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this
connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/gitlab/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
diff --git a/backend/plugins/jenkins/api/connection_api.go
b/backend/plugins/jenkins/api/connection_api.go
index ea6ee046a..d3dc5947f 100644
--- a/backend/plugins/jenkins/api/connection_api.go
+++ b/backend/plugins/jenkins/api/connection_api.go
@@ -147,7 +147,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Tags plugins/jenkins
// @Success 200 {object} models.JenkinsConnection
// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this
connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/jenkins/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
diff --git a/backend/plugins/jira/api/connection_api.go
b/backend/plugins/jira/api/connection_api.go
index 8297ac5d8..b47ad0aee 100644
--- a/backend/plugins/jira/api/connection_api.go
+++ b/backend/plugins/jira/api/connection_api.go
@@ -192,7 +192,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Tags plugins/jira
// @Success 200 {object} models.JiraConnection
// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this
connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/jira/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
diff --git a/backend/plugins/sonarqube/api/blueprint_v200.go
b/backend/plugins/sonarqube/api/blueprint_v200.go
index f1feff666..cd396541b 100644
--- a/backend/plugins/sonarqube/api/blueprint_v200.go
+++ b/backend/plugins/sonarqube/api/blueprint_v200.go
@@ -18,19 +18,22 @@ limitations under the License.
package api
import (
+ "context"
"fmt"
"net/http"
"net/url"
- "github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
coreModels "github.com/apache/incubator-devlake/core/models"
"github.com/apache/incubator-devlake/core/models/domainlayer"
"github.com/apache/incubator-devlake/core/models/domainlayer/codequality"
"github.com/apache/incubator-devlake/core/models/domainlayer/didgen"
"github.com/apache/incubator-devlake/core/plugin"
+ "github.com/apache/incubator-devlake/core/utils"
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/helpers/srvhelper"
"github.com/apache/incubator-devlake/plugins/sonarqube/models"
+ "github.com/apache/incubator-devlake/plugins/sonarqube/tasks"
)
func MakeDataSourcePipelinePlanV200(
@@ -38,12 +41,28 @@ func MakeDataSourcePipelinePlanV200(
connectionId uint64,
bpScopes []*coreModels.BlueprintScope,
) (coreModels.PipelinePlan, []plugin.Scope, errors.Error) {
- plan := make(coreModels.PipelinePlan, len(bpScopes))
- plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, plan,
bpScopes, connectionId)
+ // load connection, scope and scopeConfig from the db
+ connection, err := dsHelper.ConnSrv.FindByPk(connectionId)
if err != nil {
return nil, nil, err
}
- scopes, err := makeScopesV200(bpScopes, connectionId)
+ scopeDetails, err := dsHelper.ScopeSrv.MapScopeDetails(connectionId,
bpScopes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // needed for the connection to populate its access tokens
+ // if AppKey authentication method is selected
+ _, err = helper.NewApiClientFromConnection(context.TODO(), basicRes,
connection)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ plan, err := makeDataSourcePipelinePlanV200(subtaskMetas, scopeDetails,
connection)
+ if err != nil {
+ return nil, nil, err
+ }
+ scopes, err := makeScopesV200(scopeDetails, connection)
if err != nil {
return nil, nil, err
}
@@ -53,57 +72,59 @@ func MakeDataSourcePipelinePlanV200(
func makeDataSourcePipelinePlanV200(
subtaskMetas []plugin.SubTaskMeta,
- plan coreModels.PipelinePlan,
- bpScopes []*coreModels.BlueprintScope,
- connectionId uint64,
+ scopeDetails []*srvhelper.ScopeDetail[models.SonarqubeProject,
models.SonarqubeScopeConfig],
+ connection *models.SonarqubeConnection,
) (coreModels.PipelinePlan, errors.Error) {
- for i, bpScope := range bpScopes {
+ plan := make(coreModels.PipelinePlan, len(scopeDetails))
+ for i, scopeDetail := range scopeDetails {
stage := plan[i]
if stage == nil {
stage = coreModels.PipelineStage{}
}
- // construct task options for Sonarqube
- options := make(map[string]interface{})
- options["connectionId"] = connectionId
- options["projectKey"] = bpScope.ScopeId
-
- subtasks, err := helper.MakePipelinePlanSubtasks(subtaskMetas,
plugin.DOMAIN_TYPES)
- if err != nil {
- return nil, err
+
+ scope, scopeConfig := scopeDetail.Scope, scopeDetail.ScopeConfig
+ // construct task options
+ if utils.StringsContains(scopeConfig.Entities,
plugin.DOMAIN_TYPE_CODE_QUALITY) {
+ task, err := helper.MakePipelinePlanTask(
+ "sonarqube",
+ subtaskMetas,
+ nil,
+ tasks.SonarqubeOptions{
+ ConnectionId: scope.ConnectionId,
+ ProjectKey: scope.ProjectKey,
+ },
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ stage = append(stage, task)
+ plan[i] = stage
}
- stage = append(stage, &coreModels.PipelineTask{
- Plugin: "sonarqube",
- Subtasks: subtasks,
- Options: options,
- })
- plan[i] = stage
}
return plan, nil
}
-func makeScopesV200(bpScopes []*coreModels.BlueprintScope, connectionId
uint64) ([]plugin.Scope, errors.Error) {
+func makeScopesV200(
+ scopeDetails []*srvhelper.ScopeDetail[models.SonarqubeProject,
models.SonarqubeScopeConfig],
+ connection *models.SonarqubeConnection,
+) ([]plugin.Scope, errors.Error) {
scopes := make([]plugin.Scope, 0)
- for _, bpScope := range bpScopes {
- sonarqubeProject := &models.SonarqubeProject{}
- // get repo from db
- err := basicRes.GetDal().First(sonarqubeProject,
- dal.Where("connection_id = ? and project_key = ?",
- connectionId, bpScope.ScopeId))
- if err != nil {
- return nil, errors.Default.Wrap(err, fmt.Sprintf("fail
to find sonarqube project %s", bpScope.ScopeId))
- }
+ for _, scopeDetail := range scopeDetails {
+ sonarqubeProject, scopeConfig := scopeDetail.Scope,
scopeDetail.ScopeConfig
// add board to scopes
- // if utils.StringsContains(bpScope.Entities,
plugin.DOMAIN_TYPE_CODE_QUALITY) {
- stProject := &codequality.CqProject{
- DomainEntity: domainlayer.DomainEntity{
- Id:
didgen.NewDomainIdGenerator(&models.SonarqubeProject{}).Generate(sonarqubeProject.ConnectionId,
sonarqubeProject.ProjectKey),
- },
- Name: sonarqubeProject.Name,
+ if utils.StringsContains(scopeConfig.Entities,
plugin.DOMAIN_TYPE_CODE_QUALITY) {
+ domainBoard := &codequality.CqProject{
+ DomainEntity: domainlayer.DomainEntity{
+ Id:
didgen.NewDomainIdGenerator(&models.SonarqubeProject{}).Generate(sonarqubeProject.ConnectionId,
sonarqubeProject.ProjectKey),
+ },
+ Name: sonarqubeProject.Name,
+ }
+ scopes = append(scopes, domainBoard)
}
- scopes = append(scopes, stProject)
- // }
}
+
return scopes, nil
}
diff --git a/backend/plugins/sonarqube/api/blueprint_v200_test.go
b/backend/plugins/sonarqube/api/blueprint_v200_test.go
deleted file mode 100644
index 365548f77..000000000
--- a/backend/plugins/sonarqube/api/blueprint_v200_test.go
+++ /dev/null
@@ -1,104 +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 api
-
-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"
- mockcontext "github.com/apache/incubator-devlake/mocks/core/context"
- mockdal "github.com/apache/incubator-devlake/mocks/core/dal"
- mockplugin "github.com/apache/incubator-devlake/mocks/core/plugin"
- "github.com/apache/incubator-devlake/plugins/sonarqube/models"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-func TestMakeDataSourcePipelinePlanV200(t *testing.T) {
- mockMeta := mockplugin.NewPluginMeta(t)
-
mockMeta.On("RootPkgPath").Return("github.com/apache/incubator-devlake/plugins/sonarqube")
- mockMeta.On("Name").Return("sonarqube").Maybe()
- err := plugin.RegisterPlugin("sonarqube", mockMeta)
- assert.Nil(t, err)
- bs := &coreModels.BlueprintScope{
- ScopeId: "f5a50c63-2e8f-4107-9014-853f6f467757",
- }
-
- bpScopes := make([]*coreModels.BlueprintScope, 0)
- bpScopes = append(bpScopes, bs)
- plan := make(coreModels.PipelinePlan, len(bpScopes))
- plan, err = makeDataSourcePipelinePlanV200(nil, plan, bpScopes,
uint64(1))
- assert.Nil(t, err)
- basicRes = NewMockBasicRes()
-
- scopes, err := makeScopesV200(bpScopes, uint64(1))
- assert.Nil(t, err)
-
- expectPlan := coreModels.PipelinePlan{
- coreModels.PipelineStage{
- {
- Plugin: "sonarqube",
- Subtasks: []string{},
- Options: map[string]interface{}{
- "connectionId": uint64(1),
- "projectKey":
"f5a50c63-2e8f-4107-9014-853f6f467757",
- },
- },
- },
- }
- assert.Equal(t, expectPlan, plan)
-
- expectScopes := make([]plugin.Scope, 0)
- sonarqubeProject := &codequality.CqProject{
- DomainEntity: domainlayer.DomainEntity{
- Id:
"sonarqube:SonarqubeProject:1:f5a50c63-2e8f-4107-9014-853f6f467757",
- },
- Name: "aerosolve",
- }
-
- expectScopes = append(expectScopes, sonarqubeProject)
- assert.Equal(t, expectScopes, scopes)
-}
-
-// NewMockBasicRes FIXME ...
-func NewMockBasicRes() *mockcontext.BasicRes {
- sonarqubeProject := &models.SonarqubeProject{
- Scope: common.Scope{
- ConnectionId: 1,
- },
- ProjectKey: "f5a50c63-2e8f-4107-9014-853f6f467757",
- Name: "aerosolve",
- }
-
- mockRes := new(mockcontext.BasicRes)
- mockDal := new(mockdal.Dal)
-
- mockDal.On("First", mock.Anything, mock.Anything).Run(func(args
mock.Arguments) {
- dst := args.Get(0).(*models.SonarqubeProject)
- *dst = *sonarqubeProject
- }).Return(nil).Once()
-
- mockRes.On("GetDal").Return(mockDal)
- mockRes.On("GetConfig", mock.Anything).Return("")
-
- return mockRes
-}
diff --git a/backend/plugins/sonarqube/api/connection.go
b/backend/plugins/sonarqube/api/connection_api.go
similarity index 82%
rename from backend/plugins/sonarqube/api/connection.go
rename to backend/plugins/sonarqube/api/connection_api.go
index cb70e715f..6da210221 100644
--- a/backend/plugins/sonarqube/api/connection.go
+++ b/backend/plugins/sonarqube/api/connection_api.go
@@ -103,10 +103,9 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/{connectionId}/test [POST]
func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- connection := &models.SonarqubeConnection{}
- err := connectionHelper.First(connection, input.Params)
+ connection, err := dsHelper.ConnApi.FindByPk(input)
if err != nil {
- return nil, errors.BadInput.Wrap(err, "find connection from db")
+ return nil, err
}
// test connection
return testConnection(context.TODO(), connection.SonarqubeConn)
@@ -122,13 +121,7 @@ func TestExistingConnection(input
*plugin.ApiResourceInput) (*plugin.ApiResource
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections [POST]
func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // update from request and save to database
- connection := &models.SonarqubeConnection{}
- err := connectionHelper.Create(connection, input)
- if err != nil {
- return nil, err
- }
- return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
+ return dsHelper.ConnApi.Post(input)
}
// PatchConnection patch sonarqube connection
@@ -142,12 +135,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId} [PATCH]
func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- connection := &models.SonarqubeConnection{}
- err := connectionHelper.Patch(connection, input)
- if err != nil {
- return nil, err
- }
- return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
+ return dsHelper.ConnApi.Patch(input)
}
// DeleteConnection delete a sonarqube connection
@@ -157,18 +145,11 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Param connectionId path int false "connection ID"
// @Success 200 {object} models.SonarqubeConnection
// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this
connection"
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- conn := &models.SonarqubeConnection{}
- output, err := connectionHelper.Delete(conn, input)
- if err != nil {
- return output, err
- }
- output.Body = conn.Sanitize()
- return output, nil
-
+ return dsHelper.ConnApi.Delete(input)
}
// ListConnections get all sonarqube connections
@@ -180,15 +161,7 @@ func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections [GET]
func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- var connections []models.SonarqubeConnection
- err := connectionHelper.List(&connections)
- if err != nil {
- return nil, err
- }
- for idx, c := range connections {
- connections[idx] = c.Sanitize()
- }
- return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
+ return dsHelper.ConnApi.GetAll(input)
}
// GetConnection get sonarqube connection detail
@@ -201,7 +174,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId} [GET]
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connection := &models.SonarqubeConnection{}
- err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
+ return dsHelper.ConnApi.GetDetail(input)
}
diff --git a/backend/plugins/sonarqube/api/init.go
b/backend/plugins/sonarqube/api/init.go
index 32d1e65b2..25ec647f6 100644
--- a/backend/plugins/sonarqube/api/init.go
+++ b/backend/plugins/sonarqube/api/init.go
@@ -26,43 +26,20 @@ import (
)
var vld *validator.Validate
-var connectionHelper *api.ConnectionApiHelper
-var scopeHelper *api.ScopeApiHelper[models.SonarqubeConnection,
models.SonarqubeProject, interface{}]
-var remoteHelper *api.RemoteApiHelper[models.SonarqubeConnection,
models.SonarqubeProject, models.SonarqubeApiProject, api.NoRemoteGroupResponse]
var basicRes context.BasicRes
+
var dsHelper *api.DsHelper[models.SonarqubeConnection,
models.SonarqubeProject, models.SonarqubeScopeConfig]
+var raProxy *api.DsRemoteApiProxyHelper[models.SonarqubeConnection]
+var raScopeList *api.DsRemoteApiScopeListHelper[models.SonarqubeConnection,
models.SonarqubeProject, SonarqubeRemotePagination]
+var raScopeSearch
*api.DsRemoteApiScopeSearchHelper[models.SonarqubeConnection,
models.SonarqubeProject]
func Init(br context.BasicRes, p plugin.PluginMeta) {
-
basicRes = br
vld = validator.New()
- connectionHelper = api.NewConnectionHelper(
- basicRes,
- vld,
- p.Name(),
- )
- params := &api.ReflectionParameters{
- ScopeIdFieldName: "ProjectKey",
- ScopeIdColumnName: "project_key",
- RawScopeParamName: "ProjectKey",
- SearchScopeParamName: "name",
- }
- scopeHelper = api.NewScopeHelper[models.SonarqubeConnection,
models.SonarqubeProject, any](
- basicRes,
- vld,
- connectionHelper,
- api.NewScopeDatabaseHelperImpl[models.SonarqubeConnection,
models.SonarqubeProject, any](
- basicRes, connectionHelper, params),
- params,
- nil,
- )
- remoteHelper = api.NewRemoteHelper[models.SonarqubeConnection,
models.SonarqubeProject, models.SonarqubeApiProject, api.NoRemoteGroupResponse](
- basicRes,
- vld,
- connectionHelper,
- )
dsHelper = api.NewDataSourceHelper[
- models.SonarqubeConnection, models.SonarqubeProject,
models.SonarqubeScopeConfig,
+ models.SonarqubeConnection,
+ models.SonarqubeProject,
+ models.SonarqubeScopeConfig,
](
br,
p.Name(),
@@ -73,4 +50,11 @@ func Init(br context.BasicRes, p plugin.PluginMeta) {
nil,
nil,
)
+ raProxy =
api.NewDsRemoteApiProxyHelper[models.SonarqubeConnection](dsHelper.ConnApi.ModelApiHelper)
+ raScopeList = api.NewDsRemoteApiScopeListHelper[
+ models.SonarqubeConnection,
+ models.SonarqubeProject,
+ SonarqubeRemotePagination,
+ ](raProxy, listSonarqubeRemoteScopes)
+ raScopeSearch =
api.NewDsRemoteApiScopeSearchHelper[models.SonarqubeConnection,
models.SonarqubeProject](raProxy, searchSonarqubeRemoteProjects)
}
diff --git a/backend/plugins/sonarqube/api/proxy.go
b/backend/plugins/sonarqube/api/proxy.go
deleted file mode 100644
index da50350a7..000000000
--- a/backend/plugins/sonarqube/api/proxy.go
+++ /dev/null
@@ -1,61 +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 api
-
-import (
- "context"
- "io"
-
- "github.com/apache/incubator-devlake/core/errors"
- "github.com/apache/incubator-devlake/core/plugin"
- helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
- "github.com/apache/incubator-devlake/plugins/sonarqube/models"
-)
-
-// Proxy proxy api request to upstream sonarqube
-// @Summary proxy api request to upstream sonarqube
-// @Description Proxy HTTP GET request to the sonarqube behind this connection.
-// @Tags plugins/sonarqube
-// @Param connectionId path int false "connection ID"
-// @Param path path string false "API Path"
-// @Success 200 {object} interface{} "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/sonarqube/connections/{connectionId}/proxy/rest/{path}
[GET]
-func Proxy(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connection := &models.SonarqubeConnection{}
- err := connectionHelper.First(connection, input.Params)
- if err != nil {
- return nil, err
- }
- apiClient, err := helper.NewApiClientFromConnection(context.TODO(),
basicRes, connection)
- if err != nil {
- return nil, err
- }
- resp, err := apiClient.Get(input.Params["path"], input.Query, nil)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- body, err := errors.Convert01(io.ReadAll(resp.Body))
- if err != nil {
- return nil, err
- }
- return &plugin.ApiResourceOutput{Status: resp.StatusCode, ContentType:
resp.Header.Get("Content-Type"), Body: body}, nil
-}
diff --git a/backend/plugins/sonarqube/api/remote.go
b/backend/plugins/sonarqube/api/remote.go
deleted file mode 100644
index f836ce093..000000000
--- a/backend/plugins/sonarqube/api/remote.go
+++ /dev/null
@@ -1,116 +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 api
-
-import (
- gocontext "context"
- "fmt"
- "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/pluginhelper/api"
- "github.com/apache/incubator-devlake/plugins/sonarqube/models"
- "net/url"
-)
-
-// RemoteScopes list all available scope for users
-// @Summary list all available scope for users
-// @Description list all available scope for users
-// @Tags plugins/sonarqube
-// @Accept application/json
-// @Param connectionId path int false "connection ID"
-// @Param pageToken query string false "page Token"
-// @Success 200 {object} api.RemoteScopesOutput
-// @Failure 400 {object} shared.ApiBody "Bad Request"
-// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/sonarqube/connections/{connectionId}/remote-scopes [GET]
-func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return remoteHelper.GetScopesFromRemote(input,
- nil,
- func(basicRes context.BasicRes, gid string, queryData
*api.RemoteQueryData, connection models.SonarqubeConnection)
([]models.SonarqubeApiProject, errors.Error) {
- query := initialQuery(queryData)
- // create api client
- apiClient, err :=
api.NewApiClientFromConnection(gocontext.TODO(), basicRes, &connection)
- if err != nil {
- return nil, err
- }
-
- res, err := apiClient.Get("projects/search", query, nil)
- if err != nil {
- return nil, err
- }
-
- var resBody struct {
- Data []models.SonarqubeApiProject
`json:"components"`
- }
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
-
- return resBody.Data, nil
- })
-}
-
-// SearchRemoteScopes use the Search API and only return project
-// @Summary use the Search API and only return project
-// @Description use the Search API and only return project
-// @Tags plugins/sonarqube
-// @Accept application/json
-// @Param connectionId path int false "connection ID"
-// @Param search query string false "search keyword"
-// @Param page query int false "page number"
-// @Param pageSize query int false "page size per page"
-// @Success 200 {object} api.SearchRemoteScopesOutput
-// @Failure 400 {object} shared.ApiBody "Bad Request"
-// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/sonarqube/connections/{connectionId}/search-remote-scopes
[GET]
-func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return remoteHelper.SearchRemoteScopes(input,
- func(basicRes context.BasicRes, queryData *api.RemoteQueryData,
connection models.SonarqubeConnection) ([]models.SonarqubeApiProject,
errors.Error) {
- query := initialQuery(queryData)
- query.Set("q", queryData.Search[0])
- // create api client
- apiClient, err :=
api.NewApiClientFromConnection(gocontext.TODO(), basicRes, &connection)
- if err != nil {
- return nil, err
- }
-
- // request search
- res, err := apiClient.Get("projects/search", query, nil)
- if err != nil {
- return nil, err
- }
- var resBody struct {
- Data []models.SonarqubeApiProject
`json:"components"`
- }
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
-
- return resBody.Data, nil
- })
-}
-
-func initialQuery(queryData *api.RemoteQueryData) url.Values {
- query := url.Values{}
- query.Set("p", fmt.Sprintf("%v", queryData.Page))
- query.Set("ps", fmt.Sprintf("%v", queryData.PerPage))
- return query
-}
diff --git a/backend/plugins/sonarqube/api/remote_api.go
b/backend/plugins/sonarqube/api/remote_api.go
new file mode 100644
index 000000000..167925a7f
--- /dev/null
+++ b/backend/plugins/sonarqube/api/remote_api.go
@@ -0,0 +1,160 @@
+/*
+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 api
+
+import (
+ "fmt"
+ "net/url"
+
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/core/plugin"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ dsmodels
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/models"
+ "github.com/apache/incubator-devlake/plugins/sonarqube/models"
+)
+
+type SonarqubeRemotePagination struct {
+ Page int `json:"p"`
+ PageSize int `json:"ps"`
+}
+
+func querySonarqubeProjects(
+ apiClient plugin.ApiClient,
+ keyword string,
+ page SonarqubeRemotePagination,
+) (
+ children []dsmodels.DsRemoteApiScopeListEntry[models.SonarqubeProject],
+ nextPage *SonarqubeRemotePagination,
+ err errors.Error,
+) {
+ if page.PageSize == 0 {
+ page.PageSize = 100
+ }
+ if page.Page == 0 {
+ page.Page = 1
+ }
+ res, err := apiClient.Get("projects/search", url.Values{
+ "p": {fmt.Sprintf("%v", page.Page)},
+ "ps": {fmt.Sprintf("%v", page.PageSize)},
+ "q": {keyword},
+ }, nil)
+ if err != nil {
+ return
+ }
+
+ resBody := struct {
+ Paging struct {
+ PageIndex int `json:"pageIndex"`
+ PageSize int `json:"pageSize"`
+ Total int `json:"total"`
+ } `json:"paging"`
+ Components []*models.SonarqubeApiProject
+ }{}
+
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return
+ }
+
+ for _, project := range resBody.Components {
+ children = append(children,
dsmodels.DsRemoteApiScopeListEntry[models.SonarqubeProject]{
+ Type: api.RAS_ENTRY_TYPE_SCOPE,
+ Id: fmt.Sprintf("%v", project.ProjectKey),
+ ParentId: nil,
+ Name: project.Name,
+ FullName: project.Name,
+ Data: project.ConvertApiScope(),
+ })
+ }
+
+ return
+}
+
+func listSonarqubeRemoteScopes(
+ connection *models.SonarqubeConnection,
+ apiClient plugin.ApiClient,
+ groupId string,
+ page SonarqubeRemotePagination,
+) (
+ children []dsmodels.DsRemoteApiScopeListEntry[models.SonarqubeProject],
+ nextPage *SonarqubeRemotePagination,
+ err errors.Error,
+) {
+ return querySonarqubeProjects(apiClient, "", page)
+}
+
+// RemoteScopes list all available scopes on the remote server
+// @Summary list all available scopes on the remote server
+// @Description list all available scopes on the remote server
+// @Accept application/json
+// @Param connectionId path int false "connection ID"
+// @Param groupId query string false "group ID"
+// @Param pageToken query string false "page Token"
+// @Failure 400 {object} shared.ApiBody "Bad Request"
+// @Failure 500 {object} shared.ApiBody "Internal Error"
+// @Success 200 {object}
dsmodels.DsRemoteApiScopeList[models.SonarqubeProject]
+// @Tags plugins/sonarqube
+// @Router /plugins/sonarqube/connections/{connectionId}/remote-scopes [GET]
+func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
+ return raScopeList.Get(input)
+}
+
+func searchSonarqubeRemoteProjects(
+ apiClient plugin.ApiClient,
+ params *dsmodels.DsRemoteApiScopeSearchParams,
+) (
+ children []dsmodels.DsRemoteApiScopeListEntry[models.SonarqubeProject],
+ err errors.Error,
+) {
+ if params.Page == 0 {
+ params.Page = 1
+ }
+ page := SonarqubeRemotePagination{
+ Page: params.Page,
+ PageSize: params.PageSize,
+ }
+ children, _, err = querySonarqubeProjects(apiClient, params.Search,
page)
+ return
+}
+
+// SearchRemoteScopes searches scopes on the remote server
+// @Summary searches scopes on the remote server
+// @Description searches scopes on the remote server
+// @Accept application/json
+// @Param connectionId path int false "connection ID"
+// @Param search query string false "search"
+// @Param page query int false "page number"
+// @Param pageSize query int false "page size per page"
+// @Failure 400 {object} shared.ApiBody "Bad Request"
+// @Failure 500 {object} shared.ApiBody "Internal Error"
+// @Success 200 {object}
dsmodels.DsRemoteApiScopeList[models.SonarqubeProject] "the parentIds are
always null"
+// @Tags plugins/sonarqube
+// @Router /plugins/sonarqube/connections/{connectionId}/search-remote-scopes
[GET]
+func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return raScopeSearch.Get(input)
+}
+
+// @Summary Remote server API proxy
+// @Description Forward API requests to the specified remote server
+// @Param connectionId path int true "connection ID"
+// @Param path path string true "path to a API endpoint"
+// @Tags plugins/sonarqube
+// @Router /plugins/sonarqube/connections/{connectionId}/proxy/{path} [GET]
+func Proxy(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
+ return raProxy.Proxy(input)
+}
diff --git a/backend/plugins/sonarqube/api/scope.go
b/backend/plugins/sonarqube/api/scope_api.go
similarity index 86%
rename from backend/plugins/sonarqube/api/scope.go
rename to backend/plugins/sonarqube/api/scope_api.go
index 7ef286fda..2e7b46fbf 100644
--- a/backend/plugins/sonarqube/api/scope.go
+++ b/backend/plugins/sonarqube/api/scope_api.go
@@ -22,14 +22,12 @@ import (
"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/helpers/srvhelper"
"github.com/apache/incubator-devlake/plugins/sonarqube/models"
)
-type ScopeRes struct {
- models.SonarqubeProject
-}
-
-type ScopeReq api.ScopeReq[models.SonarqubeProject]
+type PutScopesReqBody api.PutScopesReqBody[models.SonarqubeProject]
+type ScopeDetail api.ScopeDetail[models.SonarqubeProject,
srvhelper.NoScopeConfig]
// PutScope create or update sonarqube project
// @Summary create or update sonarqube project
@@ -37,14 +35,17 @@ type ScopeReq api.ScopeReq[models.SonarqubeProject]
// @Tags plugins/sonarqube
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param scope body ScopeReq true "json"
+// @Param scope body PutScopesReqBody true "json"
// @Success 200 {object} []models.SonarqubeProject
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes [PUT]
func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
// decode request body to scope, deal with lastAnalysisDate format
- data := input.Body["data"].([]interface{})
+ data, ok := input.Body["data"].([]interface{})
+ if !ok {
+ return nil, errors.BadInput.New("invalid `data`")
+ }
for _, item := range data {
dateStr, ok :=
item.(map[string]interface{})["lastAnalysisDate"].(string)
if !ok {
@@ -59,7 +60,7 @@ func PutScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
}
- return scopeHelper.Put(input)
+ return dsHelper.ScopeApi.PutMultiple(input)
}
// UpdateScope patch to sonarqube project
@@ -75,7 +76,7 @@ func PutScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{scopeId}
[PATCH]
func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return scopeHelper.Update(input)
+ return dsHelper.ScopeApi.Patch(input)
}
// GetScopeList get Sonarqube projects
@@ -87,12 +88,12 @@ func UpdateScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
// @Param pageSize query int false "page size, default 50"
// @Param page query int false "page size, default 1"
// @Param blueprints query bool false "also return blueprints using these
scopes as part of the payload"
-// @Success 200 {object} []ScopeRes
+// @Success 200 {object} []ScopeDetail
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes [GET]
func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return scopeHelper.GetScopeList(input)
+ return dsHelper.ScopeApi.GetPage(input)
}
// GetScope get one Sonarqube project
@@ -101,12 +102,12 @@ func GetScopeList(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Tags plugins/sonarqube
// @Param connectionId path int false "connection ID"
// @Param scopeId path string false "project key"
-// @Success 200 {object} ScopeRes
+// @Success 200 {object} ScopeDetail
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{scopeId} [GET]
func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return scopeHelper.GetScope(input)
+ return dsHelper.ScopeApi.GetScopeDetail(input)
}
// DeleteScope delete plugin data associated with the scope and optionally the
scope itself
@@ -118,9 +119,9 @@ func GetScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
// @Param delete_data_only query bool false "Only delete the scope data, not
the scope itself"
// @Success 200
// @Failure 400 {object} shared.ApiBody "Bad Request"
-// @Failure 409 {object} api.ScopeRefDoc "References exist to this scope"
+// @Failure 409 {object} srvhelper.DsRefs "References exist to this scope"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{scopeId}
[DELETE]
func DeleteScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return scopeHelper.Delete(input)
+ return dsHelper.ScopeApi.Delete(input)
}
diff --git a/backend/plugins/sonarqube/impl/impl.go
b/backend/plugins/sonarqube/impl/impl.go
index f3fa16bd7..9fbef9213 100644
--- a/backend/plugins/sonarqube/impl/impl.go
+++ b/backend/plugins/sonarqube/impl/impl.go
@@ -136,14 +136,13 @@ func (p Sonarqube) PrepareTaskData(taskCtx
plugin.TaskContext, options map[strin
TaskStartTime: time.Now(),
}
// even we have project in _tool_sonaqube_projects, we still need to
collect project to update LastAnalysisDate
- var scope models.SonarqubeProject
var apiProject *models.SonarqubeApiProject
apiProject, err = api.GetApiProject(op.ProjectKey, apiClient)
if err != nil {
return nil, err
}
logger.Debug(fmt.Sprintf("Current project: %s", apiProject.ProjectKey))
- scope = apiProject.ConvertApiScope().(models.SonarqubeProject)
+ scope := apiProject.ConvertApiScope()
scope.ConnectionId = op.ConnectionId
err = taskCtx.GetDal().CreateOrUpdate(&scope)
if err != nil {
diff --git a/backend/plugins/sonarqube/models/sonarqube_project.go
b/backend/plugins/sonarqube/models/sonarqube_project.go
index fd2d49d32..d99c437cc 100644
--- a/backend/plugins/sonarqube/models/sonarqube_project.go
+++ b/backend/plugins/sonarqube/models/sonarqube_project.go
@@ -23,7 +23,6 @@ import (
)
var _ plugin.ToolLayerScope = (*SonarqubeProject)(nil)
-var _ plugin.ApiScope = (*SonarqubeApiProject)(nil)
type SonarqubeProject struct {
common.Scope `mapstructure:",squash"`
@@ -68,8 +67,8 @@ type SonarqubeApiProject struct {
}
// Convert the API response to our DB model instance
-func (sonarqubeApiProject SonarqubeApiProject) ConvertApiScope()
plugin.ToolLayerScope {
- sonarqubeProject := SonarqubeProject{
+func (sonarqubeApiProject *SonarqubeApiProject) ConvertApiScope()
*SonarqubeProject {
+ return &SonarqubeProject{
ProjectKey: sonarqubeApiProject.ProjectKey,
Name: sonarqubeApiProject.Name,
Qualifier: sonarqubeApiProject.Qualifier,
@@ -77,7 +76,6 @@ func (sonarqubeApiProject SonarqubeApiProject)
ConvertApiScope() plugin.ToolLaye
LastAnalysisDate: sonarqubeApiProject.LastAnalysisDate,
Revision: sonarqubeApiProject.Revision,
}
- return sonarqubeProject
}
type SonarqubeApiParams struct {
diff --git a/backend/plugins/sonarqube/tasks/task_data.go
b/backend/plugins/sonarqube/tasks/task_data.go
index cec529707..1d6ab3f9c 100644
--- a/backend/plugins/sonarqube/tasks/task_data.go
+++ b/backend/plugins/sonarqube/tasks/task_data.go
@@ -28,9 +28,8 @@ type SonarqubeOptions struct {
// options means some custom params required by plugin running.
// Such As How many rows do your want
// You can use it in subtasks, and you need to pass it to main.go and
pipelines.
- ConnectionId uint64 `json:"connectionId"`
- ProjectKey string `json:"projectKey"`
- Tasks []string `json:"tasks,omitempty"`
+ ConnectionId uint64 `json:"connectionId"`
+ ProjectKey string `json:"projectKey"`
api.CollectorOptions `mapstructure:",squash"`
}
diff --git a/backend/test/e2e/manual/gitlab/gitlab_test.go
b/backend/test/e2e/manual/gitlab/gitlab_test.go
index af6247aa5..2b8b5abb6 100644
--- a/backend/test/e2e/manual/gitlab/gitlab_test.go
+++ b/backend/test/e2e/manual/gitlab/gitlab_test.go
@@ -76,8 +76,8 @@ func TestGitlabPlugin(t *testing.T) {
plugin.DOMAIN_TYPE_CODE,
plugin.DOMAIN_TYPE_CODE_REVIEW,
},
+ Name: "config-1",
},
- Name: "config-1",
PrType: "",
PrComponent: "",
PrBodyClosePattern: "",