From e037be3dd670825ccd61a74aae106ada9b3d7932 Mon Sep 17 00:00:00 2001 From: Ryo Kusnadi Date: Wed, 4 Nov 2026 04:54:18 +0700 Subject: [PATCH] fix(jira): send startAt and maxResults when collecting worklogs Signed-off-by: Ryo Kusnadi --- .../plugins/jira/tasks/worklog_collector.go | 17 +++--- .../jira/tasks/worklog_collector_test.go | 52 +++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 backend/plugins/jira/tasks/worklog_collector_test.go diff --git a/backend/plugins/jira/tasks/worklog_collector.go b/backend/plugins/jira/tasks/worklog_collector.go index 8d31a1919d4..ab4d3fdcb88 100644 --- a/backend/plugins/jira/tasks/worklog_collector.go +++ b/backend/plugins/jira/tasks/worklog_collector.go @@ -19,6 +19,7 @@ package tasks import ( "encoding/json" + "fmt" "net/http" "net/url" "reflect" @@ -85,12 +86,7 @@ func CollectWorklogs(taskCtx plugin.SubTaskContext) errors.Error { UrlTemplate: "api/2/issue/{{ .Input.IssueId }}/worklog", PageSize: 50, GetTotalPages: GetTotalPagesFromResponse, - Query: func(reqData *api.RequestData) (url.Values, errors.Error) { - // According to the following resources, the worklogs API returns all worklogs without pagination - // https://community.atlassian.com/t5/Jira-questions/Worklog-Pagination/qaq-p/117614 - // https://community.atlassian.com/t5/Jira-questions/Worklog-Pagination-JIRA-REST-API/qaq-p/2173832 - return nil, nil - }, + Query: buildWorklogQuery, ResponseParser: func(res *http.Response) ([]json.RawMessage, errors.Error) { var data struct { Worklogs []json.RawMessage `json:"worklogs"` @@ -110,3 +106,12 @@ func CollectWorklogs(taskCtx plugin.SubTaskContext) errors.Error { return apiCollector.Execute() } + +// buildWorklogQuery sets the page offset and size. GetTotalPagesFromResponse makes the collector +// request one URL per page, so without startAt every page would return the first worklogs again. +func buildWorklogQuery(reqData *api.RequestData) (url.Values, errors.Error) { + query := url.Values{} + query.Set("startAt", fmt.Sprintf("%v", reqData.Pager.Skip)) + query.Set("maxResults", fmt.Sprintf("%v", reqData.Pager.Size)) + return query, nil +} diff --git a/backend/plugins/jira/tasks/worklog_collector_test.go b/backend/plugins/jira/tasks/worklog_collector_test.go new file mode 100644 index 00000000000..502a7ad0653 --- /dev/null +++ b/backend/plugins/jira/tasks/worklog_collector_test.go @@ -0,0 +1,52 @@ +/* +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 tasks + +import ( + "testing" + + "github.com/apache/devlake/helpers/pluginhelper/api" +) + +func TestBuildWorklogQuery(t *testing.T) { + tests := []struct { + name string + pager api.Pager + startAt string + maxResults string + }{ + {"first page", api.Pager{Page: 1, Skip: 0, Size: 50}, "0", "50"}, + {"second page", api.Pager{Page: 2, Skip: 50, Size: 50}, "50", "50"}, + {"tenth page", api.Pager{Page: 10, Skip: 450, Size: 50}, "450", "50"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pager := tt.pager + query, err := buildWorklogQuery(&api.RequestData{Pager: &pager}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got := query.Get("startAt"); got != tt.startAt { + t.Errorf("startAt = %q, want %q", got, tt.startAt) + } + if got := query.Get("maxResults"); got != tt.maxResults { + t.Errorf("maxResults = %q, want %q", got, tt.maxResults) + } + }) + } +}