This is an automated email from the ASF dual-hosted git repository.
warren 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 c6714ef2f fix(plugins): refactor jira jenkins and sonarqube (#4667)
c6714ef2f is described below
commit c6714ef2f72fdf0d56fbc32636c4d5c54f5fc389
Author: Warren Chen <[email protected]>
AuthorDate: Wed Mar 15 13:24:03 2023 +0800
fix(plugins): refactor jira jenkins and sonarqube (#4667)
---
backend/helpers/pluginhelper/api/scope_helper.go | 15 ++-
backend/plugins/jenkins/api/init.go | 7 +
backend/plugins/jenkins/api/scope.go | 141 +++----------------
backend/plugins/jenkins/impl/impl.go | 2 +-
backend/plugins/jenkins/models/job.go | 4 +-
backend/plugins/jira/api/init.go | 13 +-
backend/plugins/jira/api/scope.go | 150 +++------------------
backend/plugins/jira/impl/impl.go | 2 +-
backend/plugins/jira/models/board.go | 4 +-
backend/plugins/sonarqube/api/init.go | 13 +-
backend/plugins/sonarqube/api/remote.go | 6 +
backend/plugins/sonarqube/api/scope.go | 115 ++--------------
backend/plugins/sonarqube/impl/impl.go | 2 +-
.../plugins/sonarqube/models/sonarqube_project.go | 4 +-
14 files changed, 94 insertions(+), 384 deletions(-)
diff --git a/backend/helpers/pluginhelper/api/scope_helper.go
b/backend/helpers/pluginhelper/api/scope_helper.go
index 57e508726..749372831 100644
--- a/backend/helpers/pluginhelper/api/scope_helper.go
+++ b/backend/helpers/pluginhelper/api/scope_helper.go
@@ -81,7 +81,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input
*plugin.ApiResourceInput) (*
var req struct {
Data []*Scope `json:"data"`
}
- err := errors.Convert(mapstructure.Decode(input.Body, &req))
+ err := errors.Convert(DecodeMapStruct(input.Body, &req))
if err != nil {
return nil, errors.BadInput.Wrap(err, "decoding Github repo
error")
}
@@ -174,8 +174,12 @@ func (c *ScopeApiHelper[Conn, Scope, Tr])
GetScopeList(input *plugin.ApiResource
}
var ruleIds []uint64
- for _, structValue := range scopes {
- ruleId :=
reflect.ValueOf(structValue).Elem().FieldByName("TransformationRuleId").Uint()
+ for _, scope := range scopes {
+ valueRepoRuleId :=
reflect.ValueOf(scope).Elem().FieldByName("TransformationRuleId")
+ if !valueRepoRuleId.IsValid() {
+ return &plugin.ApiResourceOutput{Body: scopes, Status:
http.StatusOK}, nil
+ }
+ ruleId :=
reflect.ValueOf(scope).Elem().FieldByName("TransformationRuleId").Uint()
if ruleId > 0 {
ruleIds = append(ruleIds, ruleId)
}
@@ -209,6 +213,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input
*plugin.ApiResourceInpu
return nil, err
}
db := c.db
+
query := dal.Where(fmt.Sprintf("connection_id = ? AND %s = ?",
fieldName), connectionId, scopeId)
var scope Scope
err = db.First(&scope, query)
@@ -218,6 +223,10 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input
*plugin.ApiResourceInpu
if err != nil {
return nil, err
}
+ valueRepoRuleId :=
reflect.ValueOf(scope).FieldByName("TransformationRuleId")
+ if !valueRepoRuleId.IsValid() {
+ return &plugin.ApiResourceOutput{Body: scope, Status:
http.StatusOK}, nil
+ }
repoRuleId :=
reflect.ValueOf(scope).FieldByName("TransformationRuleId").Uint()
var rule Tr
if repoRuleId > 0 {
diff --git a/backend/plugins/jenkins/api/init.go
b/backend/plugins/jenkins/api/init.go
index d92c2b334..40c3b7104 100644
--- a/backend/plugins/jenkins/api/init.go
+++ b/backend/plugins/jenkins/api/init.go
@@ -20,11 +20,13 @@ package api
import (
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/jenkins/models"
"github.com/go-playground/validator/v10"
)
var vld *validator.Validate
var connectionHelper *api.ConnectionApiHelper
+var scopeHelper *api.ScopeApiHelper[models.JenkinsConnection,
models.JenkinsJob, models.JenkinsTransformationRule]
var basicRes context.BasicRes
func Init(br context.BasicRes) {
@@ -34,4 +36,9 @@ func Init(br context.BasicRes) {
basicRes,
vld,
)
+ scopeHelper = api.NewScopeHelper[models.JenkinsConnection,
models.JenkinsJob, models.JenkinsTransformationRule](
+ basicRes,
+ vld,
+ connectionHelper,
+ )
}
diff --git a/backend/plugins/jenkins/api/scope.go
b/backend/plugins/jenkins/api/scope.go
index ccade6104..0c932a22c 100644
--- a/backend/plugins/jenkins/api/scope.go
+++ b/backend/plugins/jenkins/api/scope.go
@@ -18,26 +18,19 @@ limitations under the License.
package api
import (
- "github.com/apache/incubator-devlake/core/dal"
"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/jenkins/models"
- "net/http"
- "strconv"
"strings"
-
- "github.com/mitchellh/mapstructure"
)
-type apiJob struct {
+type ScopeRes struct {
models.JenkinsJob
TransformationRuleName string `json:"transformationRuleName,omitempty"`
}
-type req struct {
- Data []*models.JenkinsJob `json:"data"`
-}
+type ScopeReq api.ScopeReq[models.JenkinsJob]
// PutScope create or update jenkins job
// @Summary create or update jenkins job
@@ -45,36 +38,13 @@ type req struct {
// @Tags plugins/jenkins
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param scope body req true "json"
+// @Param scope body ScopeReq true "json"
// @Success 200 {object} []models.JenkinsJob
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/jenkins/connections/{connectionId}/scopes [PUT]
func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, _ := strconv.ParseUint(input.Params["connectionId"], 10,
64)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
- var jobs req
- err := errors.Convert(mapstructure.Decode(input.Body, &jobs))
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "decoding Jenkins job
error")
- }
- keeper := make(map[string]struct{})
- for _, job := range jobs.Data {
- if _, ok := keeper[job.FullName]; ok {
- return nil, errors.BadInput.New("duplicated item")
- } else {
- keeper[job.FullName] = struct{}{}
- }
- job.ConnectionId = connectionId
-
- }
- err = basicRes.GetDal().CreateOrUpdate(jobs.Data)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
JenkinsJob")
- }
- return &plugin.ApiResourceOutput{Body: jobs.Data, Status:
http.StatusOK}, nil
+ return scopeHelper.Put(input)
}
// UpdateScope patch to jenkins job
@@ -83,33 +53,15 @@ func PutScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
// @Tags plugins/jenkins
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param fullName path string false "job's full name"
+// @Param scopeId path string false "job's full name"
// @Param scope body models.JenkinsJob true "json"
// @Success 200 {object} models.JenkinsJob
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/jenkins/connections/{connectionId}/scopes/{fullName}
[PATCH]
+// @Router /plugins/jenkins/connections/{connectionId}/scopes/{scopeId} [PATCH]
func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, fullName, err := extractParam(input.Params)
- if err != nil {
- return nil, err
- }
- var job models.JenkinsJob
- job.ConnectionId = connectionId
- job.FullName = fullName
- err = basicRes.GetDal().First(&job, dal.Where("connection_id = ? AND
full_name = ?", connectionId, fullName))
- if err != nil {
- return nil, errors.Default.Wrap(err, "getting JenkinsJob error")
- }
- err = api.DecodeMapStruct(input.Body, &job)
- if err != nil {
- return nil, errors.Default.Wrap(err, "patch jenkins job error")
- }
- err = basicRes.GetDal().Update(&job)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
JenkinsJob")
- }
- return &plugin.ApiResourceOutput{Body: job, Status: http.StatusOK}, nil
+ input.Params["scopeId"] = strings.TrimLeft(input.Params["scopeId"], "/")
+ return scopeHelper.Update(input, "full_name")
}
// GetScopeList get Jenkins jobs
@@ -119,43 +71,12 @@ func UpdateScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
// @Param connectionId path int false "connection ID"
// @Param pageSize query int false "page size, default 50"
// @Param page query int false "page size, default 1"
-// @Success 200 {object} []apiJob
+// @Success 200 {object} []ScopeRes
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/jenkins/connections/{connectionId}/scopes [GET]
func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var jobs []models.JenkinsJob
- connectionId, _ := strconv.ParseUint(input.Params["connectionId"], 10,
64)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid path params")
- }
- limit, offset := api.GetLimitOffset(input.Query, "pageSize", "page")
- err := basicRes.GetDal().All(&jobs, dal.Where("connection_id = ?",
connectionId), dal.Limit(limit), dal.Offset(offset))
- if err != nil {
- return nil, err
- }
- var ruleIds []uint64
- for _, job := range jobs {
- if job.TransformationRuleId > 0 {
- ruleIds = append(ruleIds, job.TransformationRuleId)
- }
- }
- var rules []models.JenkinsTransformationRule
- if len(ruleIds) > 0 {
- err = basicRes.GetDal().All(&rules, dal.Where("id IN (?)",
ruleIds))
- if err != nil {
- return nil, err
- }
- }
- names := make(map[uint64]string)
- for _, rule := range rules {
- names[rule.ID] = rule.Name
- }
- var apiJobs []apiJob
- for _, job := range jobs {
- apiJobs = append(apiJobs, apiJob{job,
names[job.TransformationRuleId]})
- }
- return &plugin.ApiResourceOutput{Body: apiJobs, Status: http.StatusOK},
nil
+ return scopeHelper.GetScopeList(input)
}
// GetScope get one Jenkins job
@@ -163,44 +84,12 @@ func GetScopeList(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Description get one Jenkins job
// @Tags plugins/jenkins
// @Param connectionId path int false "connection ID"
-// @Param fullName path string false "job's full name"
-// @Success 200 {object} apiJob
+// @Param scopeId path string false "job's full name"
+// @Success 200 {object} ScopeRes
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/jenkins/connections/{connectionId}/scopes/{fullName} [GET]
+// @Router /plugins/jenkins/connections/{connectionId}/scopes/{scopeId} [GET]
func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var job models.JenkinsJob
- connectionId, fullName, err := extractParam(input.Params)
- if err != nil {
- return nil, err
- }
- db := basicRes.GetDal()
- err = db.First(&job, dal.Where("connection_id = ? AND full_name = ?",
connectionId, fullName))
- if db.IsErrorNotFound(err) {
- return nil, errors.NotFound.New("record not found")
- }
- if err != nil {
- return nil, err
- }
-
- var rule models.JenkinsTransformationRule
- if job.TransformationRuleId > 0 {
- err = basicRes.GetDal().First(&rule, dal.Where("id = ?",
job.TransformationRuleId))
- if err != nil {
- return nil, err
- }
- }
- return &plugin.ApiResourceOutput{Body: apiJob{job, rule.Name}, Status:
http.StatusOK}, nil
-}
-
-func extractParam(params map[string]string) (uint64, string, errors.Error) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- if connectionId == 0 {
- return 0, "", errors.BadInput.New("invalid connectionId")
- }
- fullName := strings.TrimLeft(params["fullName"], "/")
- if fullName == "" {
- return 0, "", errors.BadInput.New("invalid fullName")
- }
- return connectionId, fullName, nil
+ input.Params["scopeId"] = strings.TrimLeft(input.Params["scopeId"], "/")
+ return scopeHelper.GetScope(input, "full_name")
}
diff --git a/backend/plugins/jenkins/impl/impl.go
b/backend/plugins/jenkins/impl/impl.go
index eddc252e0..04c2a3742 100644
--- a/backend/plugins/jenkins/impl/impl.go
+++ b/backend/plugins/jenkins/impl/impl.go
@@ -173,7 +173,7 @@ func (p Jenkins) ApiResources()
map[string]map[string]plugin.ApiResourceHandler
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
- "connections/:connectionId/scopes/*fullName": {
+ "connections/:connectionId/scopes/*scopeId": {
"GET": api.GetScope,
"PATCH": api.UpdateScope,
},
diff --git a/backend/plugins/jenkins/models/job.go
b/backend/plugins/jenkins/models/job.go
index eeaaddfa9..3f328cab2 100644
--- a/backend/plugins/jenkins/models/job.go
+++ b/backend/plugins/jenkins/models/job.go
@@ -23,8 +23,8 @@ import (
// JenkinsJob db entity for jenkins job
type JenkinsJob struct {
- ConnectionId uint64 `gorm:"primaryKey"
mapstructure:"connectionId,omitempty" json:"connectionId"`
- FullName string `gorm:"primaryKey;type:varchar(255)"
mapstructure:"jobFullName" json:"jobFullName"` // "path1/path2/job name"
+ 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"
TransformationRuleId uint64
`mapstructure:"transformationRuleId,omitempty"
json:"transformationRuleId,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"
diff --git a/backend/plugins/jira/api/init.go b/backend/plugins/jira/api/init.go
index cd019a36f..a9050797e 100644
--- a/backend/plugins/jira/api/init.go
+++ b/backend/plugins/jira/api/init.go
@@ -19,19 +19,26 @@ package api
import (
"github.com/apache/incubator-devlake/core/context"
- helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/jira/models"
"github.com/go-playground/validator/v10"
)
var vld *validator.Validate
-var connectionHelper *helper.ConnectionApiHelper
+var connectionHelper *api.ConnectionApiHelper
+var scopeHelper *api.ScopeApiHelper[models.JiraConnection, models.JiraBoard,
models.JiraTransformationRule]
var basicRes context.BasicRes
func Init(br context.BasicRes) {
basicRes = br
vld = validator.New()
- connectionHelper = helper.NewConnectionHelper(
+ connectionHelper = api.NewConnectionHelper(
basicRes,
vld,
)
+ scopeHelper = api.NewScopeHelper[models.JiraConnection,
models.JiraBoard, models.JiraTransformationRule](
+ basicRes,
+ vld,
+ connectionHelper,
+ )
}
diff --git a/backend/plugins/jira/api/scope.go
b/backend/plugins/jira/api/scope.go
index 533d0bab3..7a4fabd30 100644
--- a/backend/plugins/jira/api/scope.go
+++ b/backend/plugins/jira/api/scope.go
@@ -20,11 +20,6 @@ package api
import (
"encoding/json"
"fmt"
- "io"
- "net/http"
- "strconv"
-
- "github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
@@ -32,17 +27,16 @@ import (
"github.com/apache/incubator-devlake/plugins/jira/models"
"github.com/apache/incubator-devlake/plugins/jira/tasks"
"github.com/apache/incubator-devlake/plugins/jira/tasks/apiv2models"
- "github.com/mitchellh/mapstructure"
+ "io"
+ "net/http"
)
-type apiBoard struct {
+type ScopeRes struct {
models.JiraBoard
TransformationRuleName string `json:"transformationRuleName,omitempty"`
}
-type req struct {
- Data []*models.JiraBoard `json:"data"`
-}
+type ScopeReq api.ScopeReq[models.JiraBoard]
// PutScope create or update jira board
// @Summary create or update jira board
@@ -50,39 +44,13 @@ type req struct {
// @Tags plugins/jira
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param scope body req true "json"
+// @Param scope body ScopeReq true "json"
// @Success 200 {object} []models.JiraBoard
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/jira/connections/{connectionId}/scopes [PUT]
func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
- var boards req
- err := errors.Convert(mapstructure.Decode(input.Body, &boards))
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "decoding Jira board
error")
- }
- keeper := make(map[uint64]struct{})
- for _, board := range boards.Data {
- if _, ok := keeper[board.BoardId]; ok {
- return nil, errors.BadInput.New("duplicated item")
- } else {
- keeper[board.BoardId] = struct{}{}
- }
- board.ConnectionId = connectionId
- err = verifyBoard(board)
- if err != nil {
- return nil, err
- }
- }
- err = basicRes.GetDal().CreateOrUpdate(boards.Data)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
JiraBoard")
- }
- return &plugin.ApiResourceOutput{Body: boards.Data, Status:
http.StatusOK}, nil
+ return scopeHelper.Put(input)
}
// UpdateScope patch to jira board
@@ -91,35 +59,14 @@ func PutScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
// @Tags plugins/jira
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param boardId path int false "board ID"
+// @Param scopeId path int false "board ID"
// @Param scope body models.JiraBoard true "json"
// @Success 200 {object} models.JiraBoard
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/jira/connections/{connectionId}/scopes/{boardId} [PATCH]
+// @Router /plugins/jira/connections/{connectionId}/scopes/{scopeId} [PATCH]
func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, boardId := extractParam(input.Params)
- if connectionId*boardId == 0 {
- return nil, errors.BadInput.New("invalid connectionId or
boardId")
- }
- var board models.JiraBoard
- err := basicRes.GetDal().First(&board, dal.Where("connection_id = ? AND
board_id = ?", connectionId, boardId))
- if err != nil {
- return nil, errors.Default.Wrap(err, "getting JiraBoard error")
- }
- err = api.DecodeMapStruct(input.Body, &board)
- if err != nil {
- return nil, errors.Default.Wrap(err, "patch jira board error")
- }
- err = verifyBoard(&board)
- if err != nil {
- return nil, err
- }
- err = basicRes.GetDal().Update(board)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
JiraBoard")
- }
- return &plugin.ApiResourceOutput{Body: board, Status: http.StatusOK},
nil
+ return scopeHelper.Update(input, "board_id")
}
// GetScopeList get Jira boards
@@ -129,43 +76,12 @@ func UpdateScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
// @Param connectionId path int false "connection ID"
// @Param pageSize query int false "page size, default 50"
// @Param page query int false "page size, default 1"
-// @Success 200 {object} []apiBoard
+// @Success 200 {object} []ScopeRes
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/jira/connections/{connectionId}/scopes/ [GET]
func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var boards []models.JiraBoard
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid path params")
- }
- limit, offset := api.GetLimitOffset(input.Query, "pageSize", "page")
- err := basicRes.GetDal().All(&boards, dal.Where("connection_id = ?",
connectionId), dal.Limit(limit), dal.Offset(offset))
- if err != nil {
- return nil, err
- }
- var ruleIds []uint64
- for _, board := range boards {
- if board.TransformationRuleId > 0 {
- ruleIds = append(ruleIds, board.TransformationRuleId)
- }
- }
- var rules []models.JiraTransformationRule
- if len(ruleIds) > 0 {
- err = basicRes.GetDal().All(&rules, dal.Where("id IN (?)",
ruleIds))
- if err != nil {
- return nil, err
- }
- }
- names := make(map[uint64]string)
- for _, rule := range rules {
- names[rule.ID] = rule.Name
- }
- var apiBoards []apiBoard
- for _, board := range boards {
- apiBoards = append(apiBoards, apiBoard{board,
names[board.TransformationRuleId]})
- }
- return &plugin.ApiResourceOutput{Body: apiBoards, Status:
http.StatusOK}, nil
+ return scopeHelper.GetScopeList(input)
}
// GetScope get one Jira board
@@ -173,49 +89,13 @@ func GetScopeList(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Description get one Jira board
// @Tags plugins/jira
// @Param connectionId path int false "connection ID"
-// @Param boardId path int false "board ID"
-// @Success 200 {object} models.JiraBoard
+// @Param scopeId path int false "board ID"
+// @Success 200 {object} ScopeRes
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
-// @Router /plugins/jira/connections/{connectionId}/scopes/{boardId} [GET]
+// @Router /plugins/jira/connections/{connectionId}/scopes/{scopeId} [GET]
func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var board models.JiraBoard
- connectionId, boardId := extractParam(input.Params)
- if connectionId*boardId == 0 {
- return nil, errors.BadInput.New("invalid path params")
- }
- db := basicRes.GetDal()
- err := db.First(&board, dal.Where("connection_id = ? AND board_id = ?",
connectionId, boardId))
- if db.IsErrorNotFound(err) {
- return nil, errors.NotFound.New("record not found")
- }
- if err != nil {
- return nil, err
- }
- var rule models.JiraTransformationRule
- if board.TransformationRuleId > 0 {
- err = basicRes.GetDal().First(&rule, dal.Where("id = ?",
board.TransformationRuleId))
- if err != nil {
- return nil, err
- }
- }
- return &plugin.ApiResourceOutput{Body: apiBoard{board, rule.Name},
Status: http.StatusOK}, nil
-}
-
-func extractParam(params map[string]string) (uint64, uint64) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- boardId, _ := strconv.ParseUint(params["boardId"], 10, 64)
- return connectionId, boardId
-}
-
-func verifyBoard(board *models.JiraBoard) errors.Error {
- if board.ConnectionId == 0 {
- return errors.BadInput.New("invalid connectionId")
- }
- if board.BoardId == 0 {
- return errors.BadInput.New("invalid boardId")
- }
- return nil
+ return scopeHelper.GetScope(input, "board_id")
}
func GetApiJira(op *tasks.JiraOptions, apiClient aha.ApiClientAbstract)
(*apiv2models.Board, errors.Error) {
diff --git a/backend/plugins/jira/impl/impl.go
b/backend/plugins/jira/impl/impl.go
index fb9a6ea85..3663a672d 100644
--- a/backend/plugins/jira/impl/impl.go
+++ b/backend/plugins/jira/impl/impl.go
@@ -283,7 +283,7 @@ func (p Jira) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},
- "connections/:connectionId/scopes/:boardId": {
+ "connections/:connectionId/scopes/:scopeId": {
"GET": api.GetScope,
"PATCH": api.UpdateScope,
},
diff --git a/backend/plugins/jira/models/board.go
b/backend/plugins/jira/models/board.go
index 5992df979..82a737a64 100644
--- a/backend/plugins/jira/models/board.go
+++ b/backend/plugins/jira/models/board.go
@@ -23,8 +23,8 @@ import (
type JiraBoard struct {
common.NoPKModel `json:"-" mapstructure:"-"`
- ConnectionId uint64 `json:"connectionId"
mapstructure:"connectionId" gorm:"primaryKey"`
- BoardId uint64 `json:"boardId" mapstructure:"boardId"
gorm:"primaryKey"`
+ ConnectionId uint64 `json:"connectionId"
mapstructure:"connectionId" validate:"required" gorm:"primaryKey"`
+ BoardId uint64 `json:"boardId" mapstructure:"boardId"
validate:"required" gorm:"primaryKey"`
TransformationRuleId uint64 `json:"transformationRuleId,omitempty"
mapstructure:"transformationRuleId"`
ProjectId uint `json:"projectId" mapstructure:"projectId"`
Name string `json:"name" mapstructure:"name"
gorm:"type:varchar(255)"`
diff --git a/backend/plugins/sonarqube/api/init.go
b/backend/plugins/sonarqube/api/init.go
index cd019a36f..54c9c2bff 100644
--- a/backend/plugins/sonarqube/api/init.go
+++ b/backend/plugins/sonarqube/api/init.go
@@ -19,19 +19,26 @@ package api
import (
"github.com/apache/incubator-devlake/core/context"
- helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/sonarqube/models"
"github.com/go-playground/validator/v10"
)
var vld *validator.Validate
-var connectionHelper *helper.ConnectionApiHelper
+var connectionHelper *api.ConnectionApiHelper
+var scopeHelper *api.ScopeApiHelper[models.SonarqubeConnection,
models.SonarqubeProject, interface{}]
var basicRes context.BasicRes
func Init(br context.BasicRes) {
basicRes = br
vld = validator.New()
- connectionHelper = helper.NewConnectionHelper(
+ connectionHelper = api.NewConnectionHelper(
basicRes,
vld,
)
+ scopeHelper = api.NewScopeHelper[models.SonarqubeConnection,
models.SonarqubeProject, interface{}](
+ basicRes,
+ vld,
+ connectionHelper,
+ )
}
diff --git a/backend/plugins/sonarqube/api/remote.go
b/backend/plugins/sonarqube/api/remote.go
index 02e8f05a9..ba5e18c08 100644
--- a/backend/plugins/sonarqube/api/remote.go
+++ b/backend/plugins/sonarqube/api/remote.go
@@ -296,3 +296,9 @@ func GetQueryForSearchProject(search string, page int,
perPage int) (url.Values,
query.Set("q", search)
return query, nil
}
+
+func extractParam(params map[string]string) (uint64, string) {
+ connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
+ projectKey := params["projectKey"]
+ return connectionId, projectKey
+}
diff --git a/backend/plugins/sonarqube/api/scope.go
b/backend/plugins/sonarqube/api/scope.go
index 3ec71af35..046a0d77f 100644
--- a/backend/plugins/sonarqube/api/scope.go
+++ b/backend/plugins/sonarqube/api/scope.go
@@ -18,19 +18,13 @@ limitations under the License.
package api
import (
- "net/http"
- "strconv"
-
- "github.com/apache/incubator-devlake/core/dal"
"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"
)
-type req struct {
- Data []*models.SonarqubeProject `json:"data"`
-}
+type ScopeReq api.ScopeReq[models.SonarqubeProject]
// PutScope create or update sonarqube project
// @Summary create or update sonarqube project
@@ -38,40 +32,13 @@ type req struct {
// @Tags plugins/sonarqube
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param scope body req true "json"
+// @Param scope body ScopeReq 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) {
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
- var projects req
- // As we need to process *api.Iso8601Time, we need to use
DecodeMapStruct instead of mapstructure.Decode
- err := errors.Convert(api.DecodeMapStruct(input.Body, &projects))
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "decoding Sonarqube
project error")
- }
- keeper := make(map[string]struct{})
- for _, project := range projects.Data {
- if _, ok := keeper[project.ProjectKey]; ok {
- return nil, errors.BadInput.New("duplicated item")
- } else {
- keeper[project.ProjectKey] = struct{}{}
- }
- project.ConnectionId = connectionId
- err = verifyProject(project)
- if err != nil {
- return nil, err
- }
- }
- err = basicRes.GetDal().CreateOrUpdate(projects.Data)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
SonarqubeProject")
- }
- return &plugin.ApiResourceOutput{Body: projects.Data, Status:
http.StatusOK}, nil
+ return scopeHelper.Put(input)
}
// UpdateScope patch to sonarqube project
@@ -80,35 +47,14 @@ func PutScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors
// @Tags plugins/sonarqube
// @Accept application/json
// @Param connectionId path int false "connection ID"
-// @Param projectKey path string false "project Key"
+// @Param scopeId path string false "project Key"
// @Param scope body models.SonarqubeProject 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/{projectKey}
[PATCH]
+// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{scopeId}
[PATCH]
func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, projectKey := extractParam(input.Params)
- if connectionId*uint64(len(projectKey)) == 0 {
- return nil, errors.BadInput.New("invalid connectionId or
projectKey")
- }
- var project models.SonarqubeProject
- err := basicRes.GetDal().First(&project, dal.Where("connection_id = ?
AND project_key = ?", connectionId, projectKey))
- if err != nil {
- return nil, errors.Default.Wrap(err, "getting SonarqubeProject
error")
- }
- err = api.DecodeMapStruct(input.Body, &project)
- if err != nil {
- return nil, errors.Default.Wrap(err, "patch sonarqube project
error")
- }
- err = verifyProject(&project)
- if err != nil {
- return nil, err
- }
- err = basicRes.GetDal().Update(project)
- if err != nil {
- return nil, errors.Default.Wrap(err, "error on saving
SonarqubeProject")
- }
- return &plugin.ApiResourceOutput{Body: project, Status: http.StatusOK},
nil
+ return scopeHelper.Update(input, "project_key")
}
// GetScopeList get Sonarqube projects
@@ -121,18 +67,7 @@ func UpdateScope(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId}/scopes/ [GET]
func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var projects []models.SonarqubeProject
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid path params")
- }
- limit, offset := api.GetLimitOffset(input.Query, "pageSize", "page")
- err := basicRes.GetDal().All(&projects, dal.Where("connection_id = ?",
connectionId), dal.Limit(limit), dal.Offset(offset))
- if err != nil {
- return nil, err
- }
-
- return &plugin.ApiResourceOutput{Body: projects, Status:
http.StatusOK}, nil
+ return scopeHelper.GetScopeList(input)
}
// GetScope get one Sonarqube project
@@ -140,43 +75,13 @@ func GetScopeList(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Description get one Sonarqube project
// @Tags plugins/sonarqube
// @Param connectionId path int false "connection ID"
-// @Param projectKey path string false "project key"
+// @Param scopeId path string false "project key"
// @Param pageSize query int false "page size, default 50"
// @Param page query int false "page size, default 1"
// @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/{projectKey}
[GET]
+// @Router /plugins/sonarqube/connections/{connectionId}/scopes/{scopeId} [GET]
func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- var project models.SonarqubeProject
- connectionId, projectKey := extractParam(input.Params)
- if connectionId*uint64(len(projectKey)) == 0 {
- return nil, errors.BadInput.New("invalid path params")
- }
- db := basicRes.GetDal()
- err := db.First(&project, dal.Where("connection_id = ? AND project_key
= ?", connectionId, projectKey))
- if db.IsErrorNotFound(err) {
- return nil, errors.NotFound.New("record not found")
- }
- if err != nil {
- return nil, err
- }
-
- return &plugin.ApiResourceOutput{Body: project, Status: http.StatusOK},
nil
-}
-
-func extractParam(params map[string]string) (uint64, string) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- projectKey := params["projectKey"]
- return connectionId, projectKey
-}
-
-func verifyProject(project *models.SonarqubeProject) errors.Error {
- if project.ConnectionId == 0 {
- return errors.BadInput.New("invalid connectionId")
- }
- if len(project.ProjectKey) == 0 {
- return errors.BadInput.New("invalid project key")
- }
- return nil
+ return scopeHelper.GetScope(input, "project_key")
}
diff --git a/backend/plugins/sonarqube/impl/impl.go
b/backend/plugins/sonarqube/impl/impl.go
index 74e4cf8a6..779cffc68 100644
--- a/backend/plugins/sonarqube/impl/impl.go
+++ b/backend/plugins/sonarqube/impl/impl.go
@@ -172,7 +172,7 @@ func (p Sonarqube) ApiResources()
map[string]map[string]plugin.ApiResourceHandle
"connections/:connectionId/search-remote-scopes": {
"GET": api.SearchRemoteScopes,
},
- "connections/:connectionId/scopes/:projectKey": {
+ "connections/:connectionId/scopes/:scopeId": {
"GET": api.GetScope,
"PATCH": api.UpdateScope,
},
diff --git a/backend/plugins/sonarqube/models/sonarqube_project.go
b/backend/plugins/sonarqube/models/sonarqube_project.go
index 90616b821..47fc6037d 100644
--- a/backend/plugins/sonarqube/models/sonarqube_project.go
+++ b/backend/plugins/sonarqube/models/sonarqube_project.go
@@ -24,8 +24,8 @@ import (
type SonarqubeProject struct {
common.NoPKModel `json:"-" mapstructure:"-"`
- ConnectionId uint64 `json:"connectionId"
gorm:"primaryKey"`
- ProjectKey string `json:"projectKey"
gorm:"type:varchar(64);primaryKey"`
+ ConnectionId uint64 `json:"connectionId"
validate:"required" gorm:"primaryKey"`
+ ProjectKey string `json:"projectKey"
validate:"required" gorm:"type:varchar(64);primaryKey"`
Name string `json:"name" gorm:"type:varchar(255)"`
Qualifier string `json:"qualifier"
gorm:"type:varchar(255)"`
Visibility string `json:"visibility"
gorm:"type:varchar(64)"`