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 75cbde6e4 feat: add remote api for jenkins (#5358)
75cbde6e4 is described below

commit 75cbde6e4464f37f77c76ccfe60ad0c346efd293
Author: mappjzc <[email protected]>
AuthorDate: Tue Jun 6 15:26:22 2023 +0800

    feat: add remote api for jenkins (#5358)
    
    * feat: add remote api for jenkins
    
    Add RemoteScopes API for jenkins.
    Add SearchRemoteScopes API for jenkins.
    
    Nddtfjiang <[email protected]>
    
    * fix: fix remote error
    
    Fix remote error.
    
    Nddtfjiang <[email protected]>
---
 backend/plugins/jenkins/api/init.go        |   7 ++
 backend/plugins/jenkins/api/jobs.go        |  84 ++++++++++--------
 backend/plugins/jenkins/api/remote.go      | 134 +++++++++++++++++++++++++++++
 backend/plugins/jenkins/impl/impl.go       |  28 +++---
 backend/plugins/jenkins/models/job.go      |   8 ++
 backend/plugins/jenkins/models/response.go |  26 ++++++
 6 files changed, 236 insertions(+), 51 deletions(-)

diff --git a/backend/plugins/jenkins/api/init.go 
b/backend/plugins/jenkins/api/init.go
index ae2a1e10d..c6914494a 100644
--- a/backend/plugins/jenkins/api/init.go
+++ b/backend/plugins/jenkins/api/init.go
@@ -27,6 +27,8 @@ import (
 var vld *validator.Validate
 var connectionHelper *api.ConnectionApiHelper
 var scopeHelper *api.ScopeApiHelper[models.JenkinsConnection, 
models.JenkinsJob, models.JenkinsScopeConfig]
+var remoteHelper *api.RemoteApiHelper[models.JenkinsConnection, 
models.JenkinsJob, models.Job, models.Job]
+
 var basicRes context.BasicRes
 var scHelper *api.ScopeConfigHelper[models.JenkinsScopeConfig]
 
@@ -50,6 +52,11 @@ func Init(br context.BasicRes) {
                params,
                nil,
        )
+       remoteHelper = api.NewRemoteHelper[models.JenkinsConnection, 
models.JenkinsJob, models.Job, models.Job](
+               basicRes,
+               vld,
+               connectionHelper,
+       )
        scHelper = api.NewScopeConfigHelper[models.JenkinsScopeConfig](
                basicRes,
                vld,
diff --git a/backend/plugins/jenkins/api/jobs.go 
b/backend/plugins/jenkins/api/jobs.go
index 992c11449..f413a7e32 100644
--- a/backend/plugins/jenkins/api/jobs.go
+++ b/backend/plugins/jenkins/api/jobs.go
@@ -30,55 +30,71 @@ import (
        aha 
"github.com/apache/incubator-devlake/helpers/pluginhelper/api/apihelperabstract"
 )
 
-func GetJobs(
+func GetJobsPage(
        apiClient aha.ApiClientAbstract,
        path string,
+       page int,
        pageSize int,
        callback func(job *models.Job) errors.Error,
-) errors.Error {
-       for i := 0; ; i += pageSize {
-               var data struct {
-                       Jobs []json.RawMessage `json:"jobs"`
-               }
+) (int, errors.Error) {
+       i := page * pageSize
+       var data struct {
+               Jobs []json.RawMessage `json:"jobs"`
+       }
 
-               // set query
-               query := url.Values{}
-               treeValue := 
fmt.Sprintf("jobs[name,class,url,color,base,jobs,upstreamProjects[name]]{%d,%d}",
 i, i+pageSize)
-               query.Set("tree", treeValue)
+       // set query
+       query := url.Values{}
+       treeValue := 
fmt.Sprintf("jobs[name,class,url,color,base,jobs,upstreamProjects[name]]{%d,%d}",
 i, i+pageSize)
+       query.Set("tree", treeValue)
 
-               res, err := apiClient.Get(path+"/api/json", query, nil)
-               if err != nil {
-                       return err
+       res, err := apiClient.Get(path+"/api/json", query, nil)
+       if err != nil {
+               return 0, err
+       }
+
+       err = helper.UnmarshalResponse(res, &data)
+       if err != nil {
+               // In some directories, after testing
+               // it is found that if the second page is empty, a 500 error 
will be returned.
+               // So we don't think it's an error to return 500 in this case
+               if i > 0 && res.StatusCode == http.StatusInternalServerError {
+                       return 0, nil
+               }
+               return 0, err
+       }
+
+       for _, rawJobs := range data.Jobs {
+               job := &models.Job{}
+               err1 := json.Unmarshal(rawJobs, job)
+               if err1 != nil {
+                       return len(data.Jobs), errors.Convert(err1)
                }
 
-               err = helper.UnmarshalResponse(res, &data)
+               err = callback(job)
                if err != nil {
-                       // In some directories, after testing
-                       // it is found that if the second page is empty, a 500 
error will be returned.
-                       // So we don't think it's an error to return 500 in 
this case
-                       if i > 0 && res.StatusCode == 
http.StatusInternalServerError {
-                               return nil
-                       }
-                       return err
+                       return len(data.Jobs), err
                }
+       }
 
-               for _, rawJobs := range data.Jobs {
-                       job := &models.Job{}
-                       err1 := json.Unmarshal(rawJobs, job)
-                       if err1 != nil {
-                               return errors.Convert(err1)
-                       }
+       return len(data.Jobs), nil
+}
 
-                       err = callback(job)
-                       if err != nil {
-                               return err
-                       }
+func GetJobs(
+       apiClient aha.ApiClientAbstract,
+       path string,
+       pageSize int,
+       callback func(job *models.Job) errors.Error,
+) errors.Error {
+       for i := 0; ; i++ {
+               count, err := GetJobsPage(apiClient, path, i, pageSize, 
callback)
+               if err != nil {
+                       return err
                }
-
-               if len(data.Jobs) < pageSize {
-                       return nil
+               if count < pageSize {
+                       break
                }
        }
+       return nil
 }
 
 func GetJob(
diff --git a/backend/plugins/jenkins/api/remote.go 
b/backend/plugins/jenkins/api/remote.go
new file mode 100644
index 000000000..8df6646a9
--- /dev/null
+++ b/backend/plugins/jenkins/api/remote.go
@@ -0,0 +1,134 @@
+/*
+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"
+       "strings"
+
+       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/jenkins/models"
+)
+
+// RemoteScopes list all available scope for users
+// @Summary list all available scope for users
+// @Description list all available scope for users
+// @Tags plugins/jenkins
+// @Accept application/json
+// @Param connectionId path int false "connection ID"
+// @Param groupId query string false "group 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/jenkins/connections/{connectionId}/remote-scopes [GET]
+func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
+       return remoteHelper.GetScopesFromRemote(input,
+               func(basicRes context2.BasicRes, gid string, queryData 
*api.RemoteQueryData, connection models.JenkinsConnection) ([]models.Job, 
errors.Error) {
+                       apiClient, err := 
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+                       if err != nil {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to get create apiClient")
+                       }
+
+                       var resBody []models.Job
+                       _, err = GetJobsPage(apiClient, gid, queryData.Page-1, 
queryData.PerPage, func(job *models.Job) errors.Error {
+                               // this is a group
+                               if job.Jobs != nil {
+                                       job.Path = gid
+                                       resBody = append(resBody, *job)
+                               }
+                               return nil
+                       })
+                       if err != nil {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to GetJobsPage")
+                       }
+
+                       return resBody, err
+               },
+               func(basicRes context2.BasicRes, gid string, queryData 
*api.RemoteQueryData, connection models.JenkinsConnection) ([]models.Job, 
errors.Error) {
+                       apiClient, err := 
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+                       if err != nil {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to get create apiClient")
+                       }
+
+                       var resBody []models.Job
+                       _, err = GetJobsPage(apiClient, gid, queryData.Page-1, 
queryData.PerPage, func(job *models.Job) errors.Error {
+                               // this is only a job
+                               if job.Jobs == nil {
+                                       job.Path = gid
+                                       resBody = append(resBody, *job)
+                               }
+                               return nil
+                       })
+                       if err != nil {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to GetJobsPage")
+                       }
+
+                       return resBody, err
+               })
+}
+
+// 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/jenkins
+// @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"
+// @Success 200  {object} api.SearchRemoteScopesOutput
+// @Failure 400  {object} shared.ApiBody "Bad Request"
+// @Failure 500  {object} shared.ApiBody "Internal Error"
+// @Router /plugins/jenkins/connections/{connectionId}/search-remote-scopes 
[GET]
+func SearchRemoteScopes(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, errors.Error) {
+       return remoteHelper.SearchRemoteScopes(input,
+               func(basicRes context2.BasicRes, queryData 
*api.RemoteQueryData, connection models.JenkinsConnection) ([]models.Job, 
errors.Error) {
+                       apiClient, err := 
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+                       if err != nil {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to get create apiClient")
+                       }
+
+                       var resBody []models.Job
+                       breakError := errors.Default.New("we need break from 
get all jobs for page full")
+                       count := 0
+                       pageoOffset := (queryData.Page - 1) * queryData.PerPage
+                       err = GetAllJobs(apiClient, "", "", queryData.PerPage, 
func(job *models.Job, isPath bool) errors.Error {
+                               if job.Jobs == nil {
+                                       if strings.Contains(job.FullName, 
queryData.Search[0]) {
+                                               if count >= pageoOffset {
+                                                       resBody = 
append(resBody, *job)
+                                               }
+                                               count++
+                                       }
+                                       if len(resBody) > queryData.PerPage {
+                                               return breakError
+                                       }
+                               }
+                               return nil
+                       })
+                       if err != nil && err != breakError {
+                               return nil, errors.BadInput.Wrap(err, "failed 
to get create apiClient")
+                       }
+
+                       return resBody, nil
+               })
+}
diff --git a/backend/plugins/jenkins/impl/impl.go 
b/backend/plugins/jenkins/impl/impl.go
index 62dbe55ea..e3b03cf4e 100644
--- a/backend/plugins/jenkins/impl/impl.go
+++ b/backend/plugins/jenkins/impl/impl.go
@@ -180,6 +180,12 @@ func (p Jenkins) ApiResources() 
map[string]map[string]plugin.ApiResourceHandler
                        "DELETE": api.DeleteConnection,
                        "GET":    api.GetConnection,
                },
+               "connections/:connectionId/remote-scopes": {
+                       "GET": api.RemoteScopes,
+               },
+               "connections/:connectionId/search-remote-scopes": {
+                       "GET": api.SearchRemoteScopes,
+               },
                "connections/:connectionId/scopes/*scopeId": {
                        "GET":    api.GetScope,
                        "PATCH":  api.UpdateScope,
@@ -240,7 +246,11 @@ func EnrichOptions(taskCtx plugin.TaskContext,
        err = api.GetJob(apiClient, op.JobPath, op.JobName, op.JobFullName, 
100, func(job *models.Job, isPath bool) errors.Error {
                log.Debug(fmt.Sprintf("Current job: %s", job.FullName))
                op.JobPath = job.Path
-               jenkinsJob := ConvertJobToJenkinsJob(job, op)
+               jenkinsJob := job.ConvertApiScope().(models.JenkinsJob)
+
+               jenkinsJob.ConnectionId = op.ConnectionId
+               jenkinsJob.ScopeConfigId = op.ScopeConfigId
+
                err = taskCtx.GetDal().CreateIfNotExist(jenkinsJob)
                return err
        })
@@ -267,19 +277,3 @@ func EnrichOptions(taskCtx plugin.TaskContext,
 
        return nil
 }
-
-func ConvertJobToJenkinsJob(job *models.Job, op *tasks.JenkinsOptions) 
*models.JenkinsJob {
-       return &models.JenkinsJob{
-               ConnectionId:  op.ConnectionId,
-               FullName:      job.FullName,
-               ScopeConfigId: op.ScopeConfigId,
-               Name:          job.Name,
-               Path:          job.Path,
-               Class:         job.Class,
-               Color:         job.Color,
-               Base:          job.Base,
-               Url:           job.URL,
-               Description:   job.Description,
-               PrimaryView:   job.URL + job.Path + job.Class,
-       }
-}
diff --git a/backend/plugins/jenkins/models/job.go 
b/backend/plugins/jenkins/models/job.go
index 197211577..313ec0caa 100644
--- a/backend/plugins/jenkins/models/job.go
+++ b/backend/plugins/jenkins/models/job.go
@@ -40,3 +40,11 @@ type JenkinsJob struct {
 func (JenkinsJob) TableName() string {
        return "_tool_jenkins_jobs"
 }
+
+func (j JenkinsJob) ScopeId() string {
+       return j.FullName
+}
+
+func (j JenkinsJob) ScopeName() string {
+       return j.Name
+}
diff --git a/backend/plugins/jenkins/models/response.go 
b/backend/plugins/jenkins/models/response.go
index 31db53db0..18390249a 100644
--- a/backend/plugins/jenkins/models/response.go
+++ b/backend/plugins/jenkins/models/response.go
@@ -17,6 +17,10 @@ limitations under the License.
 
 package models
 
+import (
+       "github.com/apache/incubator-devlake/core/plugin"
+)
+
 type Job struct {
        FullName         string    `gorm:"primaryKey;type:varchar(255)"`
        Path             string    `gorm:"primaryKey;type:varchar(511)"`
@@ -31,6 +35,28 @@ type Job struct {
        *PrimaryView     `json:"primaryView"`
 }
 
+func (j Job) GroupId() string {
+       return j.Path + "job/" + j.Name + "/"
+}
+
+func (j Job) GroupName() string {
+       return j.Name
+}
+
+func (j Job) ConvertApiScope() plugin.ToolLayerScope {
+       return &JenkinsJob{
+               FullName:    j.FullName,
+               Name:        j.Name,
+               Path:        j.Path,
+               Class:       j.Class,
+               Color:       j.Color,
+               Base:        j.Base,
+               Url:         j.URL,
+               Description: j.Description,
+               PrimaryView: j.URL + j.Path + j.Class,
+       }
+}
+
 type Project struct {
        Class string `json:"_class"`
        Name  string `json:"name"`

Reply via email to