This is an automated email from the ASF dual-hosted git repository.
likyh 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 8c52c986a refactor(framework): refactor search scopes (#4692)
8c52c986a is described below
commit 8c52c986abaefdc5cd3dd1db4145d5dd60fdcf22
Author: Warren Chen <[email protected]>
AuthorDate: Fri Mar 17 15:52:41 2023 +0800
refactor(framework): refactor search scopes (#4692)
---
backend/core/plugin/plugin_connection_abstract.go | 16 +-
.../helpers/pluginhelper/api/remote_api_helper.go | 197 +++++++++++-------
backend/helpers/pluginhelper/api/scope_helper.go | 10 +-
backend/plugins/bamboo/api/blueprint_v200.go | 23 ---
backend/plugins/bamboo/api/remote.go | 207 +++++++------------
backend/plugins/bamboo/impl/impl.go | 1 -
backend/plugins/bamboo/models/connection.go | 30 +--
backend/plugins/bamboo/models/project.go | 3 +-
backend/plugins/bitbucket/api/remote.go | 217 +++++++++-----------
backend/plugins/bitbucket/models/connection.go | 57 +-----
backend/plugins/gitlab/api/remote.go | 224 ++++++++-------------
backend/plugins/gitlab/models/connection.go | 63 +-----
backend/plugins/gitlab/models/project.go | 4 +
13 files changed, 400 insertions(+), 652 deletions(-)
diff --git a/backend/core/plugin/plugin_connection_abstract.go
b/backend/core/plugin/plugin_connection_abstract.go
index 92e4a5a00..157c63df0 100644
--- a/backend/core/plugin/plugin_connection_abstract.go
+++ b/backend/core/plugin/plugin_connection_abstract.go
@@ -18,13 +18,10 @@ limitations under the License.
package plugin
import (
- context2 "github.com/apache/incubator-devlake/core/context"
-
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
- "net/http"
- "net/url"
-
"github.com/apache/incubator-devlake/core/errors"
+
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
"github.com/go-playground/validator/v10"
+ "net/http"
)
// ApiConnection represents a API Connection
@@ -34,10 +31,11 @@ type ApiConnection interface {
GetRateLimitPerHour() int
}
-type ApiConnectionForRemote[T ApiGroup, S ApiScope] interface {
- ApiConnection
- GetGroup(basicRes context2.BasicRes, gid string, query url.Values)
([]T, errors.Error)
- GetScope(basicRes context2.BasicRes, gid string, query url.Values)
([]S, errors.Error)
+type QueryData struct {
+ Page int `json:"page"`
+ PerPage int `json:"per_page"`
+ Tag string `json:"tag"`
+ Search []string
}
// ApiAuthenticator is to be implemented by a Concreate Connection if
Authorization is required
diff --git a/backend/helpers/pluginhelper/api/remote_api_helper.go
b/backend/helpers/pluginhelper/api/remote_api_helper.go
index 931ccdbae..93be9e04a 100644
--- a/backend/helpers/pluginhelper/api/remote_api_helper.go
+++ b/backend/helpers/pluginhelper/api/remote_api_helper.go
@@ -26,18 +26,37 @@ import (
"github.com/apache/incubator-devlake/core/plugin"
"github.com/go-playground/validator/v10"
"net/http"
- "net/url"
+ "strconv"
)
+type RemoteScopesChild struct {
+ Type string `json:"type"`
+ ParentId *string `json:"parentId"`
+ Id string `json:"id"`
+ Name string `json:"name"`
+ Data interface{} `json:"data"`
+}
+
+type RemoteScopesOutput struct {
+ Children []RemoteScopesChild `json:"children"`
+ NextPageToken string `json:"nextPageToken"`
+}
+
+type SearchRemoteScopesOutput struct {
+ Children []RemoteScopesChild `json:"children"`
+ Page int `json:"page"`
+ PageSize int `json:"pageSize"`
+}
+
// RemoteApiHelper is used to write the CURD of connection
-type RemoteApiHelper[Conn plugin.ApiConnectionForRemote[Group, ApiScope],
Scope plugin.ToolLayerScope, ApiScope plugin.ApiScope, Group plugin.ApiGroup]
struct {
+type RemoteApiHelper[Conn plugin.ApiConnection, Scope plugin.ToolLayerScope,
ApiScope plugin.ApiScope, Group plugin.ApiGroup] struct {
basicRes coreContext.BasicRes
validator *validator.Validate
connHelper *ConnectionApiHelper
}
// NewRemoteHelper creates a ScopeHelper for connection management
-func NewRemoteHelper[Conn plugin.ApiConnectionForRemote[Group, ApiScope],
Scope plugin.ToolLayerScope, ApiScope plugin.ApiScope, Group plugin.ApiGroup](
+func NewRemoteHelper[Conn plugin.ApiConnection, Scope plugin.ToolLayerScope,
ApiScope plugin.ApiScope, Group plugin.ApiGroup](
basicRes coreContext.BasicRes,
vld *validator.Validate,
connHelper *ConnectionApiHelper,
@@ -55,37 +74,15 @@ func NewRemoteHelper[Conn
plugin.ApiConnectionForRemote[Group, ApiScope], Scope
}
}
-type RemoteScopesChild struct {
- Type string `json:"type"`
- ParentId *string `json:"parentId"`
- Id string `json:"id"`
- Name string `json:"name"`
- Data interface{} `json:"data"`
-}
-
-type RemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- NextPageToken string `json:"nextPageToken"`
-}
-
-type SearchRemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- Page int `json:"page"`
- PageSize int `json:"pageSize"`
-}
-
-type PageData struct {
- Page int `json:"page"`
- PerPage int `json:"per_page"`
- Tag string `json:"tag"`
-}
-
const remoteScopesPerPage int = 100
const TypeProject string = "scope"
const TypeGroup string = "group"
-func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, _ := ExtractFromReqParam(input.Params)
+func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(input *plugin.ApiResourceInput,
+ getGroup func(basicRes coreContext.BasicRes, gid string, queryData
*plugin.QueryData, connection Conn) ([]Group, errors.Error),
+ getScope func(basicRes coreContext.BasicRes, gid string, queryData
*plugin.QueryData, connection Conn) ([]ApiScope, errors.Error),
+) (*plugin.ApiResourceOutput, errors.Error) {
+ connectionId, _ := extractFromReqParam(input.Params)
if connectionId == 0 {
return nil, errors.BadInput.New("invalid connectionId")
}
@@ -108,7 +105,7 @@ func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(inpu
// get gid and pageData
gid := groupId[0]
- pageData, err := getPageDataFromPageToken(pageToken[0])
+ queryData, err := getPageDataFromPageToken(pageToken[0])
if err != nil {
return nil, errors.BadInput.New("failed to get paget token")
}
@@ -116,17 +113,13 @@ func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(inpu
outputBody := &RemoteScopesOutput{}
// list groups part
- if pageData.Tag == TypeGroup {
- query, err := getQueryFromPageData(pageData)
- if err != nil {
- return nil, err
- }
+ if queryData.Tag == TypeGroup {
var resBody []Group
- resBody, err = connection.GetGroup(r.basicRes, gid, query)
+ resBody, err = getGroup(r.basicRes, gid, queryData, connection)
if err != nil {
return nil, err
}
-
+ // if len(resBody) == 0, will skip the following steps, this
will happen in some plugins which don't have group
// append group to output
for _, group := range resBody {
child := RemoteScopesChild{
@@ -143,22 +136,17 @@ func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(inpu
outputBody.Children = append(outputBody.Children, child)
}
// check groups count
- if len(resBody) < pageData.PerPage {
- pageData.Tag = TypeProject
- pageData.Page = 1
- pageData.PerPage = pageData.PerPage - len(resBody)
+ if len(resBody) < queryData.PerPage {
+ queryData.Tag = TypeProject
+ queryData.Page = 1
+ queryData.PerPage = queryData.PerPage - len(resBody)
}
}
// list projects part
- if pageData.Tag == TypeProject {
- query, err := getQueryFromPageData(pageData)
- if err != nil {
- return nil, err
- }
+ if queryData.Tag == TypeProject {
var resBody []ApiScope
-
- resBody, err = connection.GetScope(r.basicRes, gid, query)
+ resBody, err = getScope(r.basicRes, gid, queryData, connection)
if err != nil {
return nil, err
}
@@ -181,18 +169,18 @@ func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(inpu
}
// check project count
- if len(resBody) < pageData.PerPage {
- pageData = nil
+ if len(resBody) < queryData.PerPage {
+ queryData = nil
}
}
// get the next page token
outputBody.NextPageToken = ""
- if pageData != nil {
- pageData.Page += 1
- pageData.PerPage = remoteScopesPerPage
+ if queryData != nil {
+ queryData.Page += 1
+ queryData.PerPage = remoteScopesPerPage
- outputBody.NextPageToken, err =
getPageTokenFromPageData(pageData)
+ outputBody.NextPageToken, err =
getPageTokenFromPageData(queryData)
if err != nil {
return nil, err
}
@@ -201,7 +189,80 @@ func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
GetScopesFromRemote(inpu
return &plugin.ApiResourceOutput{Body: outputBody, Status:
http.StatusOK}, nil
}
-func getPageTokenFromPageData(pageData *PageData) (string, errors.Error) {
+func (r *RemoteApiHelper[Conn, Scope, ApiScope, Group])
SearchRemoteScopes(input *plugin.ApiResourceInput, searchScope func(basicRes
coreContext.BasicRes, queryData *plugin.QueryData, connection Conn)
([]ApiScope, errors.Error)) (*plugin.ApiResourceOutput, errors.Error) {
+ connectionId, _ := extractFromReqParam(input.Params)
+ if connectionId == 0 {
+ return nil, errors.BadInput.New("invalid connectionId")
+ }
+
+ var connection Conn
+ err := r.connHelper.First(&connection, input.Params)
+ if err != nil {
+ return nil, err
+ }
+
+ search, ok := input.Query["search"]
+ if !ok || len(search) == 0 {
+ search = []string{""}
+ }
+
+ var p int
+ var err1 error
+ page, ok := input.Query["page"]
+ if !ok || len(page) == 0 {
+ p = 1
+ } else {
+ p, err1 = strconv.Atoi(page[0])
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi page:%s", page[0]))
+ }
+ }
+ var ps int
+ pageSize, ok := input.Query["pageSize"]
+ if !ok || len(pageSize) == 0 {
+ ps = remoteScopesPerPage
+ } else {
+ ps, err1 = strconv.Atoi(pageSize[0])
+ if err1 != nil {
+ return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi pageSize:%s", pageSize[0]))
+ }
+ }
+
+ queryData := &plugin.QueryData{
+ Page: p,
+ PerPage: ps,
+ Search: search,
+ }
+
+ var resBody []ApiScope
+ resBody, err = searchScope(r.basicRes, queryData, connection)
+ if err != nil {
+ return nil, err
+ }
+
+ outputBody := &SearchRemoteScopesOutput{}
+
+ // append project to output
+ for _, project := range resBody {
+ scope := project.ConvertApiScope()
+ child := RemoteScopesChild{
+ Type: TypeProject,
+ Id: scope.ScopeId(),
+ ParentId: nil,
+ Name: scope.ScopeName(),
+ Data: scope,
+ }
+
+ outputBody.Children = append(outputBody.Children, child)
+ }
+
+ outputBody.Page = p
+ outputBody.PageSize = ps
+
+ return &plugin.ApiResourceOutput{Body: outputBody, Status:
http.StatusOK}, nil
+}
+
+func getPageTokenFromPageData(pageData *plugin.QueryData) (string,
errors.Error) {
// Marshal json
pageTokenDecode, err := json.Marshal(pageData)
if err != nil {
@@ -212,9 +273,9 @@ func getPageTokenFromPageData(pageData *PageData) (string,
errors.Error) {
return base64.StdEncoding.EncodeToString(pageTokenDecode), nil
}
-func getPageDataFromPageToken(pageToken string) (*PageData, errors.Error) {
+func getPageDataFromPageToken(pageToken string) (*plugin.QueryData,
errors.Error) {
if pageToken == "" {
- return &PageData{
+ return &plugin.QueryData{
Page: 1,
PerPage: remoteScopesPerPage,
Tag: "group",
@@ -227,7 +288,7 @@ func getPageDataFromPageToken(pageToken string) (*PageData,
errors.Error) {
return nil, errors.Default.Wrap(err, fmt.Sprintf("decode
pageToken failed %s", pageToken))
}
// Unmarshal json
- pt := &PageData{}
+ pt := &plugin.QueryData{}
err = json.Unmarshal(pageTokenDecode, pt)
if err != nil {
return nil, errors.Default.Wrap(err, fmt.Sprintf("json
Unmarshal pageTokenDecode failed %s", pageTokenDecode))
@@ -235,21 +296,3 @@ func getPageDataFromPageToken(pageToken string)
(*PageData, errors.Error) {
return pt, nil
}
-
-func getQueryFromPageData(pageData *PageData) (url.Values, errors.Error) {
- query := url.Values{}
- query.Set("page", fmt.Sprintf("%v", pageData.Page))
- query.Set("per_page", fmt.Sprintf("%v", pageData.PerPage))
- return query, nil
-}
-
-func GetQueryForSearchProject(search string, page int, perPage int)
(url.Values, errors.Error) {
- query, err := getQueryFromPageData(&PageData{Page: page, PerPage:
perPage})
- if err != nil {
- return nil, err
- }
- query.Set("search", search)
- query.Set("scope", "projects")
-
- return query, nil
-}
diff --git a/backend/helpers/pluginhelper/api/scope_helper.go
b/backend/helpers/pluginhelper/api/scope_helper.go
index d34069ffd..749372831 100644
--- a/backend/helpers/pluginhelper/api/scope_helper.go
+++ b/backend/helpers/pluginhelper/api/scope_helper.go
@@ -86,7 +86,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input
*plugin.ApiResourceInput) (*
return nil, errors.BadInput.Wrap(err, "decoding Github repo
error")
}
// Extract the connection ID from the input.Params map
- connectionId, _ := ExtractFromReqParam(input.Params)
+ connectionId, _ := extractFromReqParam(input.Params)
if connectionId == 0 {
return nil, errors.BadInput.New("invalid connectionId or
scopeId")
}
@@ -127,7 +127,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input
*plugin.ApiResourceInput) (*
}
func (c *ScopeApiHelper[Conn, Scope, Tr]) Update(input
*plugin.ApiResourceInput, fieldName string) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, scopeId := ExtractFromReqParam(input.Params)
+ connectionId, scopeId := extractFromReqParam(input.Params)
if connectionId == 0 || len(scopeId) == 0 || scopeId == "0" {
return &plugin.ApiResourceOutput{Body: nil, Status:
http.StatusInternalServerError}, errors.BadInput.New("invalid connectionId")
@@ -158,7 +158,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) Update(input
*plugin.ApiResourceInput,
}
func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScopeList(input
*plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
- connectionId, _ := ExtractFromReqParam(input.Params)
+ connectionId, _ := extractFromReqParam(input.Params)
if connectionId == 0 {
return nil, errors.BadInput.New("invalid path params")
}
@@ -204,7 +204,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr])
GetScopeList(input *plugin.ApiResource
}
func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input
*plugin.ApiResourceInput, fieldName string) (*plugin.ApiResourceOutput,
errors.Error) {
- connectionId, scopeId := ExtractFromReqParam(input.Params)
+ connectionId, scopeId := extractFromReqParam(input.Params)
if connectionId == 0 || len(scopeId) == 0 || scopeId == "0" {
return nil, errors.BadInput.New("invalid path params")
}
@@ -262,7 +262,7 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) save(scope
interface{}) errors.Error {
return nil
}
-func ExtractFromReqParam(params map[string]string) (uint64, string) {
+func extractFromReqParam(params map[string]string) (uint64, string) {
connectionId, err := strconv.ParseUint(params["connectionId"], 10, 64)
if err != nil {
return 0, ""
diff --git a/backend/plugins/bamboo/api/blueprint_v200.go
b/backend/plugins/bamboo/api/blueprint_v200.go
index d7fd92815..3ce938993 100644
--- a/backend/plugins/bamboo/api/blueprint_v200.go
+++ b/backend/plugins/bamboo/api/blueprint_v200.go
@@ -19,8 +19,6 @@ package api
import (
"fmt"
- "net/http"
-
"github.com/apache/incubator-devlake/plugins/bamboo/models"
"github.com/apache/incubator-devlake/core/errors"
@@ -31,7 +29,6 @@ import (
"github.com/apache/incubator-devlake/core/models/domainlayer/didgen"
plugin "github.com/apache/incubator-devlake/core/plugin"
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
- aha
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
)
func MakePipelinePlanV200(
@@ -162,23 +159,3 @@ func GetTransformationRuleByproject(project
*models.BambooProject) (*models.Bamb
return transformationRules, nil
}
-
-func GetApiProject(
- projectKey string,
- apiClient aha.ApiClientAbstract,
-) (*models.ApiBambooProject, errors.Error) {
- projectRes := &models.ApiBambooProject{}
- res, err := apiClient.Get(fmt.Sprintf("project/%s.json", projectKey),
nil, nil)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- if res.StatusCode != http.StatusOK {
- return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code when
requesting project detail from %s", res.Request.URL.String()))
- }
- err = helper.UnmarshalResponse(res, projectRes)
- if err != nil {
- return nil, err
- }
- return projectRes, nil
-}
diff --git a/backend/plugins/bamboo/api/remote.go
b/backend/plugins/bamboo/api/remote.go
index 395b560f9..a70b181bc 100644
--- a/backend/plugins/bamboo/api/remote.go
+++ b/backend/plugins/bamboo/api/remote.go
@@ -20,44 +20,16 @@ package api
import (
"context"
"fmt"
- "net/http"
- "net/url"
- "strconv"
-
+ context2 "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"
+ aha
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
"github.com/apache/incubator-devlake/plugins/bamboo/models"
+ "net/http"
+ "net/url"
)
-type RemoteScopesChild struct {
- Type string `json:"type"`
- ParentId *string `json:"parentId"`
- Id string `json:"id"`
- Name string `json:"name"`
- Data interface{} `json:"data"`
-}
-
-type RemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- NextPageToken string `json:"nextPageToken"`
-}
-
-type SearchRemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- Page int `json:"page"`
- PageSize int `json:"pageSize"`
-}
-
-type PageData struct {
- Page int `json:"page"`
- PageSize int `json:"per_page"`
-}
-
-const BambooRemoteScopesPerPage int = 100
-const TypeProject string = "scope"
-const TypeGroup string = "group"
-
// RemoteScopes list all available scope for users
// @Summary list all available scope for users
// @Description list all available scope for users
@@ -66,12 +38,33 @@ const TypeGroup string = "group"
// @Param connectionId path int false "connection ID"
// @Param groupId query string false "group ID"
// @Param pageToken query string false "page Token"
-// @Success 200 {object} RemoteScopesOutput
+// @Success 200 {object} api.RemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/bamboo/connections/{connectionId}/remote-scopes [GET]
func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return remoteHelper.GetScopesFromRemote(input)
+ return remoteHelper.GetScopesFromRemote(input,
+ nil,
+ func(basicRes context2.BasicRes, gid string, queryData
*plugin.QueryData, connection models.BambooConnection)
([]models.ApiBambooProject, errors.Error) {
+ query := initialQuery(queryData)
+ // create api client
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, err
+ }
+ res, err := apiClient.Get("/project.json", query, nil)
+
+ if err != nil {
+ return nil, err
+ }
+
+ resBody := models.ApiBambooProjectResponse{}
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody.Projects.Projects, err
+ })
}
// SearchRemoteScopes use the Search API and only return project
@@ -83,112 +76,68 @@ func RemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Param search query string false "search"
// @Param page query int false "page number"
// @Param pageSize query int false "page size per page"
-// @Success 200 {object} SearchRemoteScopesOutput
+// @Success 200 {object} api.SearchRemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/bamboo/connections/{connectionId}/search-remote-scopes
[GET]
func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
-
- connection := &models.BambooConnection{}
- err := connectionHelper.First(connection, input.Params)
- if err != nil {
- return nil, err
- }
+ return remoteHelper.SearchRemoteScopes(input,
+ func(basicRes context2.BasicRes, queryData *plugin.QueryData,
connection models.BambooConnection) ([]models.ApiBambooProject, errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ query.Set("searchTerm", queryData.Search[0])
+ // request search
+ res, err := apiClient.Get("search/projects.json",
query, nil)
+ if err != nil {
+ return nil, err
+ }
+ resBody := models.ApiBambooSearchProjectResponse{}
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ var apiBambooProjects []models.ApiBambooProject
+ // append project to output
+ for _, apiResult := range resBody.SearchResults {
+ apiProject, err :=
GetApiProject(apiResult.SearchEntity.Key, apiClient)
+ if err != nil {
+ return nil, err
+ }
+
+ apiBambooProjects = append(apiBambooProjects,
*apiProject)
+ }
+ return apiBambooProjects, err
+ })
+}
- search, ok := input.Query["search"]
- if !ok || len(search) == 0 {
- search = []string{""}
- }
+func initialQuery(queryData *plugin.QueryData) url.Values {
+ query := url.Values{}
+ query.Set("showEmpty", fmt.Sprintf("%v", true))
+ query.Set("max-result", fmt.Sprintf("%v", queryData.PerPage))
+ query.Set("start-index", fmt.Sprintf("%v",
(queryData.Page-1)*queryData.PerPage))
+ return query
+}
- var p int
- var err1 error
- page, ok := input.Query["page"]
- if !ok || len(page) == 0 {
- p = 1
- } else {
- p, err1 = strconv.Atoi(page[0])
- if err != nil {
- return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi page:%s", page[0]))
- }
- }
- var ps int
- pageSize, ok := input.Query["pageSize"]
- if !ok || len(pageSize) == 0 {
- ps = BambooRemoteScopesPerPage
- } else {
- ps, err1 = strconv.Atoi(pageSize[0])
- if err1 != nil {
- return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi pageSize:%s", pageSize[0]))
- }
- }
- // create api client
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, connection)
+// move from blueprint_v200 because of cycle import
+func GetApiProject(
+ projectKey string,
+ apiClient aha.ApiClientAbstract,
+) (*models.ApiBambooProject, errors.Error) {
+ projectRes := &models.ApiBambooProject{}
+ res, err := apiClient.Get(fmt.Sprintf("project/%s.json", projectKey),
nil, nil)
if err != nil {
return nil, err
}
-
- // set query
- query := GetQueryForSearchProject(search[0], p, ps)
-
- // request search
- res, err := apiClient.Get("search/projects.json", query, nil)
- if err != nil {
- return nil, err
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code when
requesting project detail from %s", res.Request.URL.String()))
}
- resBody := models.ApiBambooSearchProjectResponse{}
- err = api.UnmarshalResponse(res, &resBody)
+ err = api.UnmarshalResponse(res, projectRes)
if err != nil {
return nil, err
}
-
- outputBody := &SearchRemoteScopesOutput{}
-
- // append project to output
- for _, apiResult := range resBody.SearchResults {
- var project models.BambooProject
- apiProject, err := GetApiProject(apiResult.SearchEntity.Key,
apiClient)
- if err != nil {
- return nil, err
- }
-
- project = apiProject.ConvertApiScope().(models.BambooProject)
- child := RemoteScopesChild{
- Type: TypeProject,
- Id: project.ProjectKey,
- ParentId: nil,
- Name: project.Name,
- Data: project,
- }
-
- outputBody.Children = append(outputBody.Children, child)
- }
-
- outputBody.Page = p
- outputBody.PageSize = ps
-
- return &plugin.ApiResourceOutput{Body: outputBody, Status:
http.StatusOK}, nil
-}
-
-func GetQueryFromPageData(pageData *PageData) url.Values {
- query := url.Values{}
- query.Set("showEmpty", fmt.Sprintf("%v", true))
- query.Set("max-result", fmt.Sprintf("%v", pageData.PageSize))
- query.Set("start-index", fmt.Sprintf("%v",
(pageData.Page-1)*pageData.PageSize))
- return query
-}
-
-func GetQueryForSearchProject(search string, page int, perPage int) url.Values
{
- query := GetQueryFromPageData(&PageData{Page: page, PageSize: perPage})
- query.Set("searchTerm", search)
-
- return query
-}
-func extractParam(params map[string]string) (uint64, string) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- projectKey := params["projectKey"]
- return connectionId, projectKey
+ return projectRes, nil
}
diff --git a/backend/plugins/bamboo/impl/impl.go
b/backend/plugins/bamboo/impl/impl.go
index 115d7432e..be0a3f10b 100644
--- a/backend/plugins/bamboo/impl/impl.go
+++ b/backend/plugins/bamboo/impl/impl.go
@@ -19,7 +19,6 @@ package impl
import (
"fmt"
-
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
diff --git a/backend/plugins/bamboo/models/connection.go
b/backend/plugins/bamboo/models/connection.go
index 0e1e4fc5b..69694a522 100644
--- a/backend/plugins/bamboo/models/connection.go
+++ b/backend/plugins/bamboo/models/connection.go
@@ -18,11 +18,9 @@ limitations under the License.
package models
import (
- "context"
"fmt"
- context2 "github.com/apache/incubator-devlake/core/context"
+ "github.com/apache/incubator-devlake/core/plugin"
"net/http"
- "net/url"
"time"
"github.com/apache/incubator-devlake/core/errors"
@@ -30,6 +28,8 @@ import (
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
)
+var _ plugin.ApiConnection = (*BambooConnection)(nil)
+
type BambooConnection struct {
api.BaseConnection `mapstructure:",squash"`
BambooConn `mapstructure:",squash"`
@@ -92,27 +92,3 @@ type ApiRepository struct {
func (BambooConnection) TableName() string {
return "_tool_bamboo_connections"
}
-
-func (g BambooConnection) GetGroup(basicRes context2.BasicRes, gid string,
query url.Values) ([]GroupResponse, errors.Error) {
- return []GroupResponse{}, nil
-}
-
-func (g BambooConnection) GetScope(basicRes context2.BasicRes, gid string,
query url.Values) ([]ApiBambooProject, errors.Error) {
- // create api client
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &g)
- if err != nil {
- return nil, err
- }
- res, err := apiClient.Get("/project.json", query, nil)
-
- if err != nil {
- return nil, err
- }
-
- resBody := ApiBambooProjectResponse{}
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
- return resBody.Projects.Projects, err
-}
diff --git a/backend/plugins/bamboo/models/project.go
b/backend/plugins/bamboo/models/project.go
index beeb2be56..2232604e6 100644
--- a/backend/plugins/bamboo/models/project.go
+++ b/backend/plugins/bamboo/models/project.go
@@ -19,9 +19,8 @@ package models
import (
"encoding/json"
- "github.com/apache/incubator-devlake/core/plugin"
-
"github.com/apache/incubator-devlake/core/models/common"
+ "github.com/apache/incubator-devlake/core/plugin"
)
var _ plugin.ToolLayerScope = (*BambooProject)(nil)
diff --git a/backend/plugins/bitbucket/api/remote.go
b/backend/plugins/bitbucket/api/remote.go
index 46c343b8a..68df6e4f1 100644
--- a/backend/plugins/bitbucket/api/remote.go
+++ b/backend/plugins/bitbucket/api/remote.go
@@ -20,44 +20,16 @@ package api
import (
"context"
"fmt"
+ context2 "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/bitbucket/models"
"net/http"
"net/url"
- "strconv"
"strings"
)
-type RemoteScopesChild struct {
- Type string `json:"type"`
- ParentId *string `json:"parentId"`
- Id string `json:"id"`
- Name string `json:"name"`
- Data interface{} `json:"data"`
-}
-
-type RemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- NextPageToken string `json:"nextPageToken"`
-}
-
-type SearchRemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- Page int `json:"page"`
- PageSize int `json:"pageSize"`
-}
-
-type PageData struct {
- Page int `json:"page"`
- PerPage int `json:"per_page"`
-}
-
-const RemoteScopesPerPage int = 100
-const TypeScope string = "scope"
-const TypeGroup string = "group"
-
// RemoteScopes list all available scope for users
// @Summary list all available scope for users
// @Description list all available scope for users
@@ -66,12 +38,63 @@ const TypeGroup string = "group"
// @Param connectionId path int false "connection ID"
// @Param groupId query string false "group ID"
// @Param pageToken query string false "page Token"
-// @Success 200 {object} RemoteScopesOutput
+// @Success 200 {object} api.RemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/bitbucket/connections/{connectionId}/remote-scopes [GET]
func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return remoteHelper.GetScopesFromRemote(input)
+ return remoteHelper.GetScopesFromRemote(input,
+ func(basicRes context2.BasicRes, gid string, queryData
*plugin.QueryData, connection models.BitbucketConnection)
([]models.GroupResponse, errors.Error) {
+ if gid != "" {
+ return nil, nil
+ }
+ query := initialQuery(queryData)
+
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ var res *http.Response
+ query.Set("sort", "workspace.slug")
+ query.Set("fields",
"values.workspace.slug,values.workspace.name,pagelen,page,size")
+ res, err =
apiClient.Get("/user/permissions/workspaces", query, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ resBody := &models.WorkspaceResponse{}
+ err = api.UnmarshalResponse(res, resBody)
+ if err != nil {
+ return nil, err
+ }
+
+ return resBody.Values, err
+ },
+ func(basicRes context2.BasicRes, gid string, queryData
*plugin.QueryData, connection models.BitbucketConnection)
([]models.BitbucketApiRepo, errors.Error) {
+ if gid == "" {
+ return nil, nil
+ }
+ query := initialQuery(queryData)
+
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ var res *http.Response
+ query.Set("fields",
"values.name,values.full_name,values.language,values.description,values.owner.username,values.created_on,values.updated_on,values.links.clone,values.links.self,pagelen,page,size")
+ // list projects part
+ res, err =
apiClient.Get(fmt.Sprintf("/repositories/%s", gid), query, nil)
+ if err != nil {
+ return nil, err
+ }
+ var resBody models.ReposResponse
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody.Values, err
+ },
+ )
}
// SearchRemoteScopes use the Search API and only return project
@@ -83,106 +106,48 @@ func RemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Param search query string false "search"
// @Param page query int false "page number"
// @Param pageSize query int false "page size per page"
-// @Success 200 {object} SearchRemoteScopesOutput
+// @Success 200 {object} api.SearchRemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/bitbucket/connections/{connectionId}/search-remote-scopes
[GET]
func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
-
- connection := &models.BitbucketConnection{}
- err := connectionHelper.First(connection, input.Params)
- if err != nil {
- return nil, err
- }
-
- search, ok := input.Query["search"]
- if !ok || len(search) == 0 {
- search = []string{""}
- }
- s := search[0]
-
- p := 1
- page, ok := input.Query["page"]
- if ok && len(page) != 0 {
- p, err = errors.Convert01(strconv.Atoi(page[0]))
- if err != nil {
- return nil, errors.BadInput.Wrap(err,
fmt.Sprintf("failed to Atoi page:%s", page[0]))
- }
- }
-
- ps := RemoteScopesPerPage
- pageSize, ok := input.Query["pageSize"]
- if ok && len(pageSize) != 0 {
- ps, err = errors.Convert01(strconv.Atoi(pageSize[0]))
- if err != nil {
- return nil, errors.BadInput.Wrap(err,
fmt.Sprintf("failed to Atoi pageSize:%s", pageSize[0]))
- }
- }
-
- // create api client
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, connection)
- if err != nil {
- return nil, err
- }
-
- // set query
- query, err := GetQueryFromPageData(&PageData{p, ps})
- if err != nil {
- return nil, err
- }
-
- // request search
- query.Set("sort", "name")
- query.Set("fields",
"values.name,values.full_name,values.language,values.description,values.owner.username,values.created_on,values.updated_on,values.links.clone,values.links.self,pagelen,page,size")
-
- gid := ``
- if strings.Contains(s, `/`) {
- gid = strings.Split(s, `/`)[0]
- s = strings.Split(s, `/`)[0]
- }
- query.Set("q", fmt.Sprintf(`name~"%s"`, s))
- // list repos part
- res, err := apiClient.Get(fmt.Sprintf("/repositories/%s", gid), query,
nil)
- if err != nil {
- return nil, err
- }
- resBody := &models.ReposResponse{}
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
-
- // set repos return
- outputBody := &SearchRemoteScopesOutput{Children: []RemoteScopesChild{}}
- for _, repo := range resBody.Values {
- child := RemoteScopesChild{
- Type: TypeScope,
- Id: repo.FullName,
- ParentId: nil,
- Name: repo.Name,
- Data: repo.ConvertApiScope(),
- }
- outputBody.Children = append(outputBody.Children, child)
- }
-
- outputBody.Page = p
- outputBody.PageSize = ps
-
- return &plugin.ApiResourceOutput{Body: outputBody, Status:
http.StatusOK}, nil
+ return remoteHelper.SearchRemoteScopes(input,
+ func(basicRes context2.BasicRes, queryData *plugin.QueryData,
connection models.BitbucketConnection) ([]models.BitbucketApiRepo,
errors.Error) {
+ // create api client
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, err
+ }
+ query := initialQuery(queryData)
+ s := queryData.Search[0]
+
+ // request search
+ query.Set("sort", "name")
+ query.Set("fields",
"values.name,values.full_name,values.language,values.description,values.owner.username,values.created_on,values.updated_on,values.links.clone,values.links.self,pagelen,page,size")
+ gid := ``
+ if strings.Contains(s, `/`) {
+ gid = strings.Split(s, `/`)[0]
+ s = strings.Split(s, `/`)[0]
+ }
+ query.Set("q", fmt.Sprintf(`name~"%s"`, s))
+ // list repos part
+ res, err :=
apiClient.Get(fmt.Sprintf("/repositories/%s", gid), query, nil)
+ if err != nil {
+ return nil, err
+ }
+ resBody := &models.ReposResponse{}
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody.Values, err
+ },
+ )
}
-func GetQueryFromPageData(pageData *PageData) (url.Values, errors.Error) {
+func initialQuery(queryData *plugin.QueryData) url.Values {
query := url.Values{}
- query.Set("page", fmt.Sprintf("%v", pageData.Page))
- query.Set("pagelen", fmt.Sprintf("%v", pageData.PerPage))
- return query, nil
-}
-func extractParam(params map[string]string) (uint64, string) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- fullName := strings.TrimLeft(params["repoId"], "/")
- return connectionId, fullName
+ query.Set("page", fmt.Sprintf("%v", queryData.Page))
+ query.Set("pagelen", fmt.Sprintf("%v", queryData.PerPage))
+ return query
}
diff --git a/backend/plugins/bitbucket/models/connection.go
b/backend/plugins/bitbucket/models/connection.go
index 6300a8deb..9db3befc5 100644
--- a/backend/plugins/bitbucket/models/connection.go
+++ b/backend/plugins/bitbucket/models/connection.go
@@ -18,18 +18,11 @@ limitations under the License.
package models
import (
- "context"
- "fmt"
- context2 "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"
- "net/http"
- "net/url"
)
-var _ plugin.ApiConnectionForRemote[GroupResponse, BitbucketApiRepo] =
(*BitbucketConnection)(nil)
-var _ plugin.ApiGroup = (*GroupResponse)(nil)
+var _ plugin.ApiConnection = (*BitbucketConnection)(nil)
// BitbucketConn holds the essential information to connect to the Bitbucket
API
type BitbucketConn struct {
@@ -46,51 +39,3 @@ type BitbucketConnection struct {
func (BitbucketConnection) TableName() string {
return "_tool_bitbucket_connections"
}
-
-func (g BitbucketConnection) GetGroup(basicRes context2.BasicRes, gid string,
query url.Values) ([]GroupResponse, errors.Error) {
- if gid != "" {
- return nil, nil
- }
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &g)
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "failed to get create
apiClient")
- }
- var res *http.Response
- query.Set("sort", "workspace.slug")
- query.Set("fields",
"values.workspace.slug,values.workspace.name,pagelen,page,size")
- res, err = apiClient.Get("/user/permissions/workspaces", query, nil)
- if err != nil {
- return nil, err
- }
-
- resBody := &WorkspaceResponse{}
- err = api.UnmarshalResponse(res, resBody)
- if err != nil {
- return nil, err
- }
-
- return resBody.Values, err
-}
-
-func (g BitbucketConnection) GetScope(basicRes context2.BasicRes, gid string,
query url.Values) ([]BitbucketApiRepo, errors.Error) {
- if gid == "" {
- return nil, nil
- }
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &g)
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "failed to get create
apiClient")
- }
- var res *http.Response
- query.Set("fields",
"values.name,values.full_name,values.language,values.description,values.owner.username,values.created_on,values.updated_on,values.links.clone,values.links.self,pagelen,page,size")
- // list projects part
- res, err = apiClient.Get(fmt.Sprintf("/repositories/%s", gid), query,
nil)
- if err != nil {
- return nil, err
- }
- var resBody ReposResponse
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
- return resBody.Values, err
-}
diff --git a/backend/plugins/gitlab/api/remote.go
b/backend/plugins/gitlab/api/remote.go
index 69875646b..62c950834 100644
--- a/backend/plugins/gitlab/api/remote.go
+++ b/backend/plugins/gitlab/api/remote.go
@@ -20,46 +20,15 @@ package api
import (
"context"
"fmt"
- "net/http"
- "net/url"
- "strconv"
-
+ context2 "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/gitlab/models"
- "github.com/apache/incubator-devlake/plugins/gitlab/tasks"
+ "net/http"
+ "net/url"
)
-type RemoteScopesChild struct {
- Type string `json:"type"`
- ParentId *string `json:"parentId"`
- Id string `json:"id"`
- Name string `json:"name"`
- Data interface{} `json:"data"`
-}
-
-type RemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- NextPageToken string `json:"nextPageToken"`
-}
-
-type SearchRemoteScopesOutput struct {
- Children []RemoteScopesChild `json:"children"`
- Page int `json:"page"`
- PageSize int `json:"pageSize"`
-}
-
-type PageData struct {
- Page int `json:"page"`
- PerPage int `json:"per_page"`
- Tag string `json:"tag"`
-}
-
-const GitlabRemoteScopesPerPage int = 100
-const TypeProject string = "scope"
-const TypeGroup string = "group"
-
// RemoteScopes list all available scope for users
// @Summary list all available scope for users
// @Description list all available scope for users
@@ -68,12 +37,64 @@ const TypeGroup string = "group"
// @Param connectionId path int false "connection ID"
// @Param groupId query string false "group ID"
// @Param pageToken query string false "page Token"
-// @Success 200 {object} RemoteScopesOutput
+// @Success 200 {object} api.RemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/gitlab/connections/{connectionId}/remote-scopes [GET]
func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return remoteHelper.GetScopesFromRemote(input)
+ return remoteHelper.GetScopesFromRemote(input,
+ func(basicRes context2.BasicRes, gid string, queryData
*plugin.QueryData, connection models.GitlabConnection) ([]models.GroupResponse,
errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ var res *http.Response
+ if gid == "" {
+ query.Set("top_level_only", "true")
+ res, err = apiClient.Get("groups", query, nil)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ res, err =
apiClient.Get(fmt.Sprintf("groups/%s/subgroups", gid), query, nil)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var resBody []models.GroupResponse
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody, err
+ },
+ func(basicRes context2.BasicRes, gid string, queryData
*plugin.QueryData, connection models.GitlabConnection)
([]models.GitlabApiProject, errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ var res *http.Response
+ if gid == "" {
+ res, err =
apiClient.Get(fmt.Sprintf("users/%d/projects", apiClient.GetData("UserId")),
query, nil)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ query.Set("with_shared", "false")
+ res, err =
apiClient.Get(fmt.Sprintf("/groups/%s/projects", gid), query, nil)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var resBody []models.GitlabApiProject
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody, err
+ })
}
// SearchRemoteScopes use the Search API and only return project
@@ -85,112 +106,41 @@ func RemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
// @Param search query string false "search"
// @Param page query int false "page number"
// @Param pageSize query int false "page size per page"
-// @Success 200 {object} SearchRemoteScopesOutput
+// @Success 200 {object} api.SearchRemoteScopesOutput
// @Failure 400 {object} shared.ApiBody "Bad Request"
// @Failure 500 {object} shared.ApiBody "Internal Error"
// @Router /plugins/gitlab/connections/{connectionId}/search-remote-scopes
[GET]
func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- connectionId, _ := extractParam(input.Params)
- if connectionId == 0 {
- return nil, errors.BadInput.New("invalid connectionId")
- }
-
- connection := &models.GitlabConnection{}
- err := connectionHelper.First(connection, input.Params)
- if err != nil {
- return nil, err
- }
-
- search, ok := input.Query["search"]
- if !ok || len(search) == 0 {
- search = []string{""}
- }
-
- var p int
- var err1 error
- page, ok := input.Query["page"]
- if !ok || len(page) == 0 {
- p = 1
- } else {
- p, err1 = strconv.Atoi(page[0])
- if err != nil {
- return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi page:%s", page[0]))
- }
- }
- var ps int
- pageSize, ok := input.Query["pageSize"]
- if !ok || len(pageSize) == 0 {
- ps = GitlabRemoteScopesPerPage
- } else {
- ps, err1 = strconv.Atoi(pageSize[0])
- if err1 != nil {
- return nil, errors.BadInput.Wrap(err1,
fmt.Sprintf("failed to Atoi pageSize:%s", pageSize[0]))
- }
- }
- // create api client
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, connection)
- if err != nil {
- return nil, err
- }
-
- // set query
- query, err := GetQueryForSearchProject(search[0], p, ps)
- if err != nil {
- return nil, err
- }
-
- // request search
- res, err := apiClient.Get("search", query, nil)
- if err != nil {
- return nil, err
- }
- resBody := []tasks.GitlabApiProject{}
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
-
- outputBody := &SearchRemoteScopesOutput{}
-
- // append project to output
- for _, project := range resBody {
- child := RemoteScopesChild{
- Type: TypeProject,
- Id: strconv.Itoa(project.GitlabId),
- ParentId: nil,
- Name: project.PathWithNamespace,
- Data: tasks.ConvertProject(&project),
- }
-
- outputBody.Children = append(outputBody.Children, child)
- }
-
- outputBody.Page = p
- outputBody.PageSize = ps
-
- return &plugin.ApiResourceOutput{Body: outputBody, Status:
http.StatusOK}, nil
+ return remoteHelper.SearchRemoteScopes(input,
+ func(basicRes context2.BasicRes, queryData *plugin.QueryData,
connection models.GitlabConnection) ([]models.GitlabApiProject, errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ query.Set("search", queryData.Search[0])
+ query.Set("scope", "projects")
+ // request search
+ res, err := apiClient.Get("search", query, nil)
+ if err != nil {
+ return nil, err
+ }
+ var resBody []models.GitlabApiProject
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ for i := 0; i < len(resBody); i++ {
+ // as we need to set PathWithNamespace to name
in SearchRemoteScopes, but interface.ScopeName will return name, so we switch it
+ resBody[i].Name, resBody[i].PathWithNamespace =
resBody[i].PathWithNamespace, resBody[i].Name
+ }
+ return resBody, err
+ })
}
-func GetQueryFromPageData(pageData *PageData) (url.Values, errors.Error) {
+func initialQuery(queryData *plugin.QueryData) url.Values {
query := url.Values{}
- query.Set("page", fmt.Sprintf("%v", pageData.Page))
- query.Set("per_page", fmt.Sprintf("%v", pageData.PerPage))
- return query, nil
-}
-
-func GetQueryForSearchProject(search string, page int, perPage int)
(url.Values, errors.Error) {
- query, err := GetQueryFromPageData(&PageData{Page: page, PerPage:
perPage})
- if err != nil {
- return nil, err
- }
- query.Set("search", search)
- query.Set("scope", "projects")
-
- return query, nil
-}
-
-func extractParam(params map[string]string) (uint64, uint64) {
- connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
- projectId, _ := strconv.ParseUint(params["projectId"], 10, 64)
- return connectionId, projectId
+ query.Set("page", fmt.Sprintf("%v", queryData.Page))
+ query.Set("per_page", fmt.Sprintf("%v", queryData.PerPage))
+ return query
}
diff --git a/backend/plugins/gitlab/models/connection.go
b/backend/plugins/gitlab/models/connection.go
index aa55a79d2..0b8f6fa91 100644
--- a/backend/plugins/gitlab/models/connection.go
+++ b/backend/plugins/gitlab/models/connection.go
@@ -18,16 +18,12 @@ limitations under the License.
package models
import (
- "context"
"fmt"
- context2 "github.com/apache/incubator-devlake/core/context"
- "github.com/apache/incubator-devlake/core/plugin"
- "net/http"
- "net/url"
-
"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/helpers/pluginhelper/api/apihelperabstract"
+ "net/http"
)
// GitlabConn holds the essential information to connect to the Gitlab API
@@ -108,8 +104,7 @@ func (conn *GitlabConn) PrepareApiClient(apiClient
apihelperabstract.ApiClientAb
return nil
}
-var _ plugin.ApiConnectionForRemote[GroupResponse, GitlabApiProject] =
(*GitlabConnection)(nil)
-var _ plugin.ApiGroup = (*GroupResponse)(nil)
+var _ plugin.ApiConnection = (*GitlabConnection)(nil)
// GitlabConnection holds GitlabConn plus ID/Name for database storage
type GitlabConnection struct {
@@ -138,55 +133,3 @@ type ApiUserResponse struct {
func (GitlabConnection) TableName() string {
return "_tool_gitlab_connections"
}
-
-func (g GitlabConnection) GetGroup(basicRes context2.BasicRes, gid string,
query url.Values) ([]GroupResponse, errors.Error) {
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &g)
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "failed to get create
apiClient")
- }
- var res *http.Response
- if gid == "" {
- query.Set("top_level_only", "true")
- res, err = apiClient.Get("groups", query, nil)
- if err != nil {
- return nil, err
- }
- } else {
- res, err = apiClient.Get(fmt.Sprintf("groups/%s/subgroups",
gid), query, nil)
- if err != nil {
- return nil, err
- }
- }
- var resBody []GroupResponse
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
- return resBody, err
-}
-
-func (g GitlabConnection) GetScope(basicRes context2.BasicRes, gid string,
query url.Values) ([]GitlabApiProject, errors.Error) {
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &g)
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "failed to get create
apiClient")
- }
- var res *http.Response
- if gid == "" {
- res, err = apiClient.Get(fmt.Sprintf("users/%d/projects",
apiClient.GetData("UserId")), query, nil)
- if err != nil {
- return nil, err
- }
- } else {
- query.Set("with_shared", "false")
- res, err = apiClient.Get(fmt.Sprintf("/groups/%s/projects",
gid), query, nil)
- if err != nil {
- return nil, err
- }
- }
- var resBody []GitlabApiProject
- err = api.UnmarshalResponse(res, &resBody)
- if err != nil {
- return nil, err
- }
- return resBody, err
-}
diff --git a/backend/plugins/gitlab/models/project.go
b/backend/plugins/gitlab/models/project.go
index af08f9128..9f9c1f1c0 100644
--- a/backend/plugins/gitlab/models/project.go
+++ b/backend/plugins/gitlab/models/project.go
@@ -82,6 +82,10 @@ func (gitlabApiProject GitlabApiProject) ConvertApiScope()
plugin.ToolLayerScope
p.ForkedFromProjectId =
gitlabApiProject.ForkedFromProject.GitlabId
p.ForkedFromProjectWebUrl =
gitlabApiProject.ForkedFromProject.WebUrl
}
+ // this might happen when GitlabConnection.SearchScopes
+ if len(p.Name) > len(p.PathWithNamespace) {
+ p.Name, p.PathWithNamespace = p.PathWithNamespace, p.Name
+ }
return p
}