This is an automated email from the ASF dual-hosted git repository.
abeizn pushed a commit to branch release-v0.16
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/release-v0.16 by this push:
new eb86e6dc1 fix: the jql time zone issue (#4932)
eb86e6dc1 is described below
commit eb86e6dc17d5b6d119e9922592ee92519e690ed9
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Apr 14 17:41:31 2023 +0800
fix: the jql time zone issue (#4932)
---
backend/plugins/jira/tasks/issue_collector.go | 34 +++++---
backend/plugins/jira/tasks/issue_collector_test.go | 93 ++++++++++++++++++++++
2 files changed, 116 insertions(+), 11 deletions(-)
diff --git a/backend/plugins/jira/tasks/issue_collector.go
b/backend/plugins/jira/tasks/issue_collector.go
index 0e60cc56d..6b36f87cb 100644
--- a/backend/plugins/jira/tasks/issue_collector.go
+++ b/backend/plugins/jira/tasks/issue_collector.go
@@ -23,6 +23,7 @@ import (
"io"
"net/http"
"net/url"
+ "time"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
@@ -66,18 +67,8 @@ func CollectIssues(taskCtx plugin.SubTaskContext)
errors.Error {
// build jql
// IMPORTANT: we have to keep paginated data in a consistence order to
avoid data-missing, if we sort issues by
// `updated`, issue will be jumping between pages if it got updated
during the collection process
- jql := "created is not null ORDER BY created ASC"
-
- // timer filter
- if data.TimeAfter != nil {
- jql = fmt.Sprintf("updated >= '%v' AND %v",
data.TimeAfter.Format("2006/01/02 15:04"), jql)
- }
-
- // diff sync
incremental := collectorWithState.IsIncremental()
- if incremental {
- jql = fmt.Sprintf("updated >= '%v' AND %v",
collectorWithState.LatestState.LatestSuccessStart.Format("2006/01/02 15:04"),
jql)
- }
+ jql := buildJQL(data.TimeAfter,
collectorWithState.LatestState.LatestSuccessStart, incremental)
err = collectorWithState.InitCollector(api.ApiCollectorArgs{
ApiClient: data.ApiClient,
@@ -144,3 +135,24 @@ func CollectIssues(taskCtx plugin.SubTaskContext)
errors.Error {
return collectorWithState.Execute()
}
+
+// buildJQL build jql based on timeAfter and incremental mode
+func buildJQL(timeAfter, latestSuccessStart *time.Time, isIncremental bool)
string {
+ jql := "ORDER BY created ASC"
+ var moment time.Time
+ if timeAfter != nil {
+ moment = *timeAfter
+ }
+ // if isIncremental is true, we should not collect data before
latestSuccessStart
+ if isIncremental {
+ // subtract 24 hours to avoid missing data due to time zone
difference
+ latest := latestSuccessStart.Add(-24 * time.Hour)
+ if latest.After(moment) {
+ moment = latest
+ }
+ }
+ if !moment.IsZero() {
+ jql = fmt.Sprintf("updated >= '%s' %s",
moment.In(time.UTC).Format("2006/01/02 15:04"), jql)
+ }
+ return jql
+}
diff --git a/backend/plugins/jira/tasks/issue_collector_test.go
b/backend/plugins/jira/tasks/issue_collector_test.go
new file mode 100644
index 000000000..3dba84ed1
--- /dev/null
+++ b/backend/plugins/jira/tasks/issue_collector_test.go
@@ -0,0 +1,93 @@
+/*
+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"
+ "time"
+)
+
+func Test_buildJQL(t *testing.T) {
+ base := time.Date(2021, 2, 3, 4, 5, 6, 7, time.UTC)
+ timeAfter := base
+ add48 := base.Add(48 * time.Hour)
+ minus48 := base.Add(-48 * time.Hour)
+ type args struct {
+ timeAfter *time.Time
+ latestSuccessStart *time.Time
+ isIncremental bool
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ }{
+ {
+ name: "test incremental",
+ args: args{
+ timeAfter: nil,
+ latestSuccessStart: nil,
+ isIncremental: false,
+ },
+ want: "ORDER BY created ASC"},
+ {
+ name: "test incremental",
+ args: args{
+ timeAfter: nil,
+ latestSuccessStart: &add48,
+ isIncremental: true,
+ },
+ want: "updated >= '2021/02/04 04:05' ORDER BY created
ASC",
+ },
+ {
+ name: "test incremental",
+ args: args{
+ timeAfter: &base,
+ latestSuccessStart: nil,
+ isIncremental: false,
+ },
+ want: "updated >= '2021/02/03 04:05' ORDER BY created
ASC",
+ },
+ {
+ name: "test incremental",
+ args: args{
+ timeAfter: &timeAfter,
+ latestSuccessStart: &add48,
+ isIncremental: true,
+ },
+ want: "updated >= '2021/02/04 04:05' ORDER BY created
ASC",
+ },
+ {
+ name: "test incremental",
+ args: args{
+ timeAfter: &timeAfter,
+ latestSuccessStart: &minus48,
+ isIncremental: true,
+ },
+ want: "updated >= '2021/02/03 04:05' ORDER BY created
ASC",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := buildJQL(tt.args.timeAfter,
tt.args.latestSuccessStart, tt.args.isIncremental); got != tt.want {
+ t.Errorf("buildJQL() = %v, want %v", got,
tt.want)
+ }
+ })
+ }
+}