This is an automated email from the ASF dual-hosted git repository.
lynwee 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 7ac45c78d fix: circleci plugin pagination (#7770)
7ac45c78d is described below
commit 7ac45c78db61e3db8534187b133a8c67163d41e0
Author: Nick Williams <[email protected]>
AuthorDate: Thu Jul 25 16:41:02 2024 +0100
fix: circleci plugin pagination (#7770)
* fix(circleci-plugin): correct page-token query param name
* fix(circleci-plugin): set default page size for circleci api requests to
20
* refactor(circleci-plugin): extract common api pagination functions to
shared source file
---------
Co-authored-by: Lynwee <[email protected]>
---
backend/plugins/circleci/tasks/job_collector.go | 40 +++++-----------------
.../plugins/circleci/tasks/pipeline_collector.go | 37 ++++----------------
backend/plugins/circleci/tasks/shared.go | 30 ++++++++++++++++
backend/plugins/circleci/tasks/task_data.go | 3 ++
.../plugins/circleci/tasks/workflow_collector.go | 40 +++++-----------------
5 files changed, 58 insertions(+), 92 deletions(-)
diff --git a/backend/plugins/circleci/tasks/job_collector.go
b/backend/plugins/circleci/tasks/job_collector.go
index 23fbedbc6..06241a547 100644
--- a/backend/plugins/circleci/tasks/job_collector.go
+++ b/backend/plugins/circleci/tasks/job_collector.go
@@ -18,15 +18,13 @@ limitations under the License.
package tasks
import (
- "encoding/json"
+ "reflect"
+
"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/circleci/models"
- "net/http"
- "net/url"
- "reflect"
)
const RAW_JOB_TABLE = "circleci_api_jobs"
@@ -63,33 +61,13 @@ func CollectJobs(taskCtx plugin.SubTaskContext)
errors.Error {
}
collector, err := api.NewApiCollector(api.ApiCollectorArgs{
- RawDataSubTaskArgs: *rawDataSubTaskArgs,
- ApiClient: data.ApiClient,
- UrlTemplate: "/v2/workflow/{{ .Input.Id }}/job",
- Input: iterator,
- GetNextPageCustomData: func(prevReqData *api.RequestData,
prevPageResponse *http.Response) (interface{}, errors.Error) {
- res := CircleciPageTokenResp[any]{}
- err := api.UnmarshalResponse(prevPageResponse, &res)
- if err != nil {
- return nil, err
- }
- if res.NextPageToken == "" {
- return nil, api.ErrFinishCollect
- }
- return res.NextPageToken, nil
- },
- Query: func(reqData *api.RequestData) (url.Values,
errors.Error) {
- query := url.Values{}
- if pageToken, ok := reqData.CustomData.(string); ok &&
pageToken != "" {
- query.Set("page_token",
reqData.CustomData.(string))
- }
- return query, nil
- },
- ResponseParser: func(res *http.Response) ([]json.RawMessage,
errors.Error) {
- data := CircleciPageTokenResp[[]json.RawMessage]{}
- err := api.UnmarshalResponse(res, &data)
- return data.Items, err
- },
+ RawDataSubTaskArgs: *rawDataSubTaskArgs,
+ ApiClient: data.ApiClient,
+ UrlTemplate: "/v2/workflow/{{ .Input.Id }}/job",
+ Input: iterator,
+ GetNextPageCustomData: ExtractNextPageToken,
+ Query: BuildQueryParamsWithPageToken,
+ ResponseParser: ParseCircleciPageTokenResp,
})
if err != nil {
logger.Error(err, "collect jobs error")
diff --git a/backend/plugins/circleci/tasks/pipeline_collector.go
b/backend/plugins/circleci/tasks/pipeline_collector.go
index 586f9ae6d..b7940e6c8 100644
--- a/backend/plugins/circleci/tasks/pipeline_collector.go
+++ b/backend/plugins/circleci/tasks/pipeline_collector.go
@@ -18,12 +18,9 @@ limitations under the License.
package tasks
import (
- "encoding/json"
"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"
)
const RAW_PIPELINE_TABLE = "circleci_api_pipelines"
@@ -43,33 +40,13 @@ func CollectPipelines(taskCtx plugin.SubTaskContext)
errors.Error {
logger := taskCtx.GetLogger()
logger.Info("collect pipelines")
collector, err := api.NewApiCollector(api.ApiCollectorArgs{
- RawDataSubTaskArgs: *rawDataSubTaskArgs,
- ApiClient: data.ApiClient,
- UrlTemplate: "/v2/project/{{ .Params.ProjectSlug
}}/pipeline",
- PageSize: int(data.Options.PageSize),
- GetNextPageCustomData: func(prevReqData *api.RequestData,
prevPageResponse *http.Response) (interface{}, errors.Error) {
- res := CircleciPageTokenResp[any]{}
- err := api.UnmarshalResponse(prevPageResponse, &res)
- if err != nil {
- return nil, err
- }
- if res.NextPageToken == "" {
- return nil, api.ErrFinishCollect
- }
- return res.NextPageToken, nil
- },
- Query: func(reqData *api.RequestData) (url.Values,
errors.Error) {
- query := url.Values{}
- if pageToken, ok := reqData.CustomData.(string); ok &&
pageToken != "" {
- query.Set("page_token",
reqData.CustomData.(string))
- }
- return query, nil
- },
- ResponseParser: func(res *http.Response) ([]json.RawMessage,
errors.Error) {
- data := CircleciPageTokenResp[[]json.RawMessage]{}
- err := api.UnmarshalResponse(res, &data)
- return data.Items, err
- },
+ RawDataSubTaskArgs: *rawDataSubTaskArgs,
+ ApiClient: data.ApiClient,
+ UrlTemplate: "/v2/project/{{ .Params.ProjectSlug
}}/pipeline",
+ PageSize: int(data.Options.PageSize),
+ GetNextPageCustomData: ExtractNextPageToken,
+ Query: BuildQueryParamsWithPageToken,
+ ResponseParser: ParseCircleciPageTokenResp,
})
if err != nil {
logger.Error(err, "collect pipelines error")
diff --git a/backend/plugins/circleci/tasks/shared.go
b/backend/plugins/circleci/tasks/shared.go
index c720daecb..998b1419c 100644
--- a/backend/plugins/circleci/tasks/shared.go
+++ b/backend/plugins/circleci/tasks/shared.go
@@ -18,6 +18,10 @@ limitations under the License.
package tasks
import (
+ "encoding/json"
+ "net/http"
+ "net/url"
+
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/models/domainlayer/didgen"
@@ -91,3 +95,29 @@ func findPipelineById(db dal.Dal, id string)
(*models.CircleciPipeline, errors.E
}
return pipeline, nil
}
+
+func ExtractNextPageToken(prevReqData *api.RequestData, prevPageResponse
*http.Response) (interface{}, errors.Error) {
+ res := CircleciPageTokenResp[any]{}
+ err := api.UnmarshalResponse(prevPageResponse, &res)
+ if err != nil {
+ return nil, err
+ }
+ if res.NextPageToken == "" {
+ return nil, api.ErrFinishCollect
+ }
+ return res.NextPageToken, nil
+}
+
+func BuildQueryParamsWithPageToken(reqData *api.RequestData) (url.Values,
errors.Error) {
+ query := url.Values{}
+ if pageToken, ok := reqData.CustomData.(string); ok && pageToken != "" {
+ query.Set("page-token", pageToken)
+ }
+ return query, nil
+}
+
+func ParseCircleciPageTokenResp(res *http.Response) ([]json.RawMessage,
errors.Error) {
+ data := CircleciPageTokenResp[[]json.RawMessage]{}
+ err := api.UnmarshalResponse(res, &data)
+ return data.Items, err
+}
diff --git a/backend/plugins/circleci/tasks/task_data.go
b/backend/plugins/circleci/tasks/task_data.go
index 960325696..ba30ba8d9 100644
--- a/backend/plugins/circleci/tasks/task_data.go
+++ b/backend/plugins/circleci/tasks/task_data.go
@@ -46,5 +46,8 @@ func DecodeAndValidateTaskOptions(options
map[string]interface{}) (*CircleciOpti
if op.ConnectionId == 0 {
return nil, errors.Default.New("connectionId is invalid")
}
+ if op.PageSize == 0 {
+ op.PageSize = 20 // CircleCI API default page size
+ }
return &op, nil
}
diff --git a/backend/plugins/circleci/tasks/workflow_collector.go
b/backend/plugins/circleci/tasks/workflow_collector.go
index a1ba0acaa..cdb4e1c36 100644
--- a/backend/plugins/circleci/tasks/workflow_collector.go
+++ b/backend/plugins/circleci/tasks/workflow_collector.go
@@ -18,15 +18,13 @@ limitations under the License.
package tasks
import (
- "encoding/json"
+ "reflect"
+
"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/circleci/models"
- "net/http"
- "net/url"
- "reflect"
)
const RAW_WORKFLOW_TABLE = "circleci_api_workflows"
@@ -63,33 +61,13 @@ func CollectWorkflows(taskCtx plugin.SubTaskContext)
errors.Error {
}
collector, err := api.NewApiCollector(api.ApiCollectorArgs{
- RawDataSubTaskArgs: *rawDataSubTaskArgs,
- ApiClient: data.ApiClient,
- UrlTemplate: "/v2/pipeline/{{ .Input.Id }}/workflow",
- Input: iterator,
- GetNextPageCustomData: func(prevReqData *api.RequestData,
prevPageResponse *http.Response) (interface{}, errors.Error) {
- res := CircleciPageTokenResp[any]{}
- err := api.UnmarshalResponse(prevPageResponse, &res)
- if err != nil {
- return nil, err
- }
- if res.NextPageToken == "" {
- return nil, api.ErrFinishCollect
- }
- return res.NextPageToken, nil
- },
- Query: func(reqData *api.RequestData) (url.Values,
errors.Error) {
- query := url.Values{}
- if pageToken, ok := reqData.CustomData.(string); ok &&
pageToken != "" {
- query.Set("page_token",
reqData.CustomData.(string))
- }
- return query, nil
- },
- ResponseParser: func(res *http.Response) ([]json.RawMessage,
errors.Error) {
- data := CircleciPageTokenResp[[]json.RawMessage]{}
- err := api.UnmarshalResponse(res, &data)
- return data.Items, err
- },
+ RawDataSubTaskArgs: *rawDataSubTaskArgs,
+ ApiClient: data.ApiClient,
+ UrlTemplate: "/v2/pipeline/{{ .Input.Id }}/workflow",
+ Input: iterator,
+ GetNextPageCustomData: ExtractNextPageToken,
+ Query: BuildQueryParamsWithPageToken,
+ ResponseParser: ParseCircleciPageTokenResp,
})
if err != nil {
logger.Error(err, "collect workflows error")