You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ab...@apache.org on 2024/01/11 08:20:05 UTC
(incubator-devlake) branch jira-filter updated: feat: add filter jql checker
This is an automated email from the ASF dual-hosted git repository.
abeizn pushed a commit to branch jira-filter
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/jira-filter by this push:
new 715466ee0 feat: add filter jql checker
715466ee0 is described below
commit 715466ee0d368031e19450a0954436d699a2a5f9
Author: abeizn <zi...@merico.dev>
AuthorDate: Thu Jan 11 16:16:31 2024 +0800
feat: add filter jql checker
---
backend/plugins/jira/impl/impl.go | 4 +
backend/plugins/jira/models/board.go | 1 +
.../migrationscripts/20240111_add_filter_jql.go | 46 +++++
.../jira/models/migrationscripts/register.go | 1 +
.../jira/tasks/board_filter_begin_collector.go | 211 +++++++++++++++++++++
.../jira/tasks/board_filter_end_collector.go | 84 ++++++++
6 files changed, 347 insertions(+)
diff --git a/backend/plugins/jira/impl/impl.go b/backend/plugins/jira/impl/impl.go
index 6686b775a..259361475 100644
--- a/backend/plugins/jira/impl/impl.go
+++ b/backend/plugins/jira/impl/impl.go
@@ -103,6 +103,8 @@ func (p Jira) Name() string {
func (p Jira) SubTaskMetas() []plugin.SubTaskMeta {
return []plugin.SubTaskMeta{
+ tasks.CollectBoardFilterBeginMeta,
+
tasks.CollectStatusMeta,
tasks.ExtractStatusMeta,
@@ -156,6 +158,8 @@ func (p Jira) SubTaskMetas() []plugin.SubTaskMeta {
tasks.ExtractAccountsMeta,
tasks.ConvertAccountsMeta,
+
+ tasks.CollectBoardFilterEndMeta,
}
}
diff --git a/backend/plugins/jira/models/board.go b/backend/plugins/jira/models/board.go
index ad4ed2b0d..267c1cdc0 100644
--- a/backend/plugins/jira/models/board.go
+++ b/backend/plugins/jira/models/board.go
@@ -33,6 +33,7 @@ type JiraBoard struct {
Name string `json:"name" mapstructure:"name" gorm:"type:varchar(255)"`
Self string `json:"self" mapstructure:"self" gorm:"type:varchar(255)"`
Type string `json:"type" mapstructure:"type" gorm:"type:varchar(100)"`
+ Jql string `json:"jql" mapstructure:"jql"`
}
func (b JiraBoard) ScopeId() string {
diff --git a/backend/plugins/jira/models/migrationscripts/20240111_add_filter_jql.go b/backend/plugins/jira/models/migrationscripts/20240111_add_filter_jql.go
new file mode 100644
index 000000000..9528cb0d1
--- /dev/null
+++ b/backend/plugins/jira/models/migrationscripts/20240111_add_filter_jql.go
@@ -0,0 +1,46 @@
+/*
+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 migrationscripts
+
+import (
+ "github.com/apache/incubator-devlake/core/context"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/helpers/migrationhelper"
+)
+
+type JiraBoard20240111 struct {
+ Jql string
+}
+
+func (JiraBoard20240111) TableName() string {
+ return "_tool_jira_boards"
+}
+
+type addFilterJQL struct{}
+
+func (script *addFilterJQL) Up(basicRes context.BasicRes) errors.Error {
+ return migrationhelper.AutoMigrateTables(basicRes, &JiraBoard20240111{})
+}
+
+func (*addFilterJQL) Version() uint64 {
+ return 20240111113738
+}
+
+func (*addFilterJQL) Name() string {
+ return "add jql to _tool_jira_boards"
+}
diff --git a/backend/plugins/jira/models/migrationscripts/register.go b/backend/plugins/jira/models/migrationscripts/register.go
index c900f202e..b4c410c9f 100644
--- a/backend/plugins/jira/models/migrationscripts/register.go
+++ b/backend/plugins/jira/models/migrationscripts/register.go
@@ -46,5 +46,6 @@ func All() []plugin.MigrationScript {
new(dropIssueAllFields),
new(modifyIssueRelationship),
new(addComponents20230412),
+ new(addFilterJQL),
}
}
diff --git a/backend/plugins/jira/tasks/board_filter_begin_collector.go b/backend/plugins/jira/tasks/board_filter_begin_collector.go
new file mode 100644
index 000000000..252289a9d
--- /dev/null
+++ b/backend/plugins/jira/tasks/board_filter_begin_collector.go
@@ -0,0 +1,211 @@
+/*
+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 (
+ "fmt"
+
+ "github.com/apache/incubator-devlake/core/dal"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/core/plugin"
+ helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/jira/models"
+)
+
+var CollectBoardFilterBeginMeta = plugin.SubTaskMeta{
+ Name: "collectBoardFilterBegin",
+ EntryPoint: CollectBoardFilterBegin,
+ EnabledByDefault: true,
+ Description: "Jira board filter jql checker before runnig",
+ DomainTypes: plugin.DOMAIN_TYPES,
+}
+
+func CollectBoardFilterBegin(taskCtx plugin.SubTaskContext) errors.Error {
+ data := taskCtx.GetData().(*JiraTaskData)
+ logger := taskCtx.GetLogger()
+ db := taskCtx.GetDal()
+ logger.Info("collect board in collectBoardFilterBegin: %d", data.Options.BoardId)
+
+ // get board filter id
+ url := fmt.Sprintf("agile/1.0/board/%d/configuration", data.Options.BoardId)
+ boardConfiguration, err := data.ApiClient.Get(url, nil, nil)
+ if err != nil {
+ return err
+ }
+ bc := &BoardConfiguration{}
+ err = helper.UnmarshalResponse(boardConfiguration, bc)
+ if err != nil {
+ return err
+ }
+ filterId := bc.Filter.ID
+ logger.Info("collect board filter:%s", filterId)
+
+ // get board filter jql
+ url = fmt.Sprintf("api/2/filter/%s", filterId)
+ filterInfo, err := data.ApiClient.Get(url, nil, nil)
+ if err != nil {
+ return err
+ }
+ fi := &FilterInfo{}
+ err = helper.UnmarshalResponse(filterInfo, fi)
+ if err != nil {
+ return err
+ }
+ jql := fi.Jql
+ logger.Info("collect board filter jql:%s", jql)
+
+ var record models.JiraBoard
+ err = db.First(&record, dal.Where("connection_id = ? AND board_id = ? ", data.Options.ConnectionId, data.Options.BoardId))
+ if err != nil {
+ return errors.Default.Wrap(err, fmt.Sprintf("error finding record in _tool_jira_boards table for connection_id:%d board_id:%d", data.Options.ConnectionId, data.Options.BoardId))
+ }
+
+ // full sync
+ syncPolicy := taskCtx.TaskContext().SyncPolicy()
+ if syncPolicy != nil && syncPolicy.FullSync {
+ if record.Jql != jql {
+ record.Jql = jql
+ err = db.Update(&record, dal.Where("connection_id = ? AND board_id = ? ", data.Options.ConnectionId, data.Options.BoardId))
+ if err != nil {
+ return errors.Default.Wrap(err, fmt.Sprintf("error updating record in _tool_jira_boards table for connection_id:%d board_id:%d", data.Options.ConnectionId, data.Options.BoardId))
+ }
+ }
+ return nil
+ }
+ // first run
+ if record.Jql == "" {
+ record.Jql = jql
+ err = db.Update(&record, dal.Where("connection_id = ? AND board_id = ? ", data.Options.ConnectionId, data.Options.BoardId))
+ if err != nil {
+ return errors.Default.Wrap(err, fmt.Sprintf("error updating record in _tool_jira_boards table for connection_id:%d board_id:%d", data.Options.ConnectionId, data.Options.BoardId))
+ }
+ return nil
+ }
+ // no change
+ if record.Jql == jql {
+ return nil
+ }
+ // change
+ if record.Jql != jql {
+ return errors.Default.New(fmt.Sprintf("board filter jql has changed for connection_id:%d board_id:%d, please use fullSync mode!!!", data.Options.ConnectionId, data.Options.BoardId))
+ }
+
+ return nil
+}
+
+type BoardConfiguration struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Self string `json:"self"`
+ Location struct {
+ Type string `json:"type"`
+ Key string `json:"key"`
+ ID string `json:"id"`
+ Self string `json:"self"`
+ Name string `json:"name"`
+ } `json:"location"`
+ Filter struct {
+ ID string `json:"id"`
+ Self string `json:"self"`
+ } `json:"filter"`
+ ColumnConfig struct {
+ Columns []struct {
+ Name string `json:"name"`
+ Statuses []struct {
+ ID string `json:"id"`
+ Self string `json:"self"`
+ } `json:"statuses"`
+ } `json:"columns"`
+ ConstraintType string `json:"constraintType"`
+ } `json:"columnConfig"`
+ Estimation struct {
+ Type string `json:"type"`
+ Field struct {
+ FieldID string `json:"fieldId"`
+ DisplayName string `json:"displayName"`
+ } `json:"field"`
+ } `json:"estimation"`
+ Ranking struct {
+ RankCustomFieldID int `json:"rankCustomFieldId"`
+ } `json:"ranking"`
+}
+
+type FilterInfo struct {
+ Self string `json:"self"`
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Owner struct {
+ Self string `json:"self"`
+ AccountID string `json:"accountId"`
+ AvatarUrls struct {
+ Four8X48 string `json:"48x48"`
+ Two4X24 string `json:"24x24"`
+ One6X16 string `json:"16x16"`
+ Three2X32 string `json:"32x32"`
+ } `json:"avatarUrls"`
+ DisplayName string `json:"displayName"`
+ Active bool `json:"active"`
+ } `json:"owner"`
+ Jql string `json:"jql"`
+ ViewURL string `json:"viewUrl"`
+ SearchURL string `json:"searchUrl"`
+ Favourite bool `json:"favourite"`
+ FavouritedCount int `json:"favouritedCount"`
+ SharePermissions []struct {
+ ID int `json:"id"`
+ Type string `json:"type"`
+ Project struct {
+ Self string `json:"self"`
+ ID string `json:"id"`
+ Key string `json:"key"`
+ AssigneeType string `json:"assigneeType"`
+ Name string `json:"name"`
+ Roles struct {
+ } `json:"roles"`
+ AvatarUrls struct {
+ Four8X48 string `json:"48x48"`
+ Two4X24 string `json:"24x24"`
+ One6X16 string `json:"16x16"`
+ Three2X32 string `json:"32x32"`
+ } `json:"avatarUrls"`
+ ProjectTypeKey string `json:"projectTypeKey"`
+ Simplified bool `json:"simplified"`
+ Style string `json:"style"`
+ Properties struct {
+ } `json:"properties"`
+ } `json:"project"`
+ } `json:"sharePermissions"`
+ EditPermissions []any `json:"editPermissions"`
+ IsWritable bool `json:"isWritable"`
+ SharedUsers struct {
+ Size int `json:"size"`
+ Items []any `json:"items"`
+ MaxResults int `json:"max-results"`
+ StartIndex int `json:"start-index"`
+ EndIndex int `json:"end-index"`
+ } `json:"sharedUsers"`
+ Subscriptions struct {
+ Size int `json:"size"`
+ Items []any `json:"items"`
+ MaxResults int `json:"max-results"`
+ StartIndex int `json:"start-index"`
+ EndIndex int `json:"end-index"`
+ } `json:"subscriptions"`
+}
diff --git a/backend/plugins/jira/tasks/board_filter_end_collector.go b/backend/plugins/jira/tasks/board_filter_end_collector.go
new file mode 100644
index 000000000..caa9dfaae
--- /dev/null
+++ b/backend/plugins/jira/tasks/board_filter_end_collector.go
@@ -0,0 +1,84 @@
+/*
+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 (
+ "fmt"
+
+ "github.com/apache/incubator-devlake/core/dal"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/core/plugin"
+ helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/jira/models"
+)
+
+var CollectBoardFilterEndMeta = plugin.SubTaskMeta{
+ Name: "collectBoardFilterEnd",
+ EntryPoint: CollectBoardFilterEnd,
+ EnabledByDefault: true,
+ Description: "Jira board filter jql checker after runnig",
+ DomainTypes: plugin.DOMAIN_TYPES,
+}
+
+func CollectBoardFilterEnd(taskCtx plugin.SubTaskContext) errors.Error {
+ data := taskCtx.GetData().(*JiraTaskData)
+ logger := taskCtx.GetLogger()
+ db := taskCtx.GetDal()
+ logger.Info("collect board in collectBoardFilterEnd: %d", data.Options.BoardId)
+
+ // get board filter id
+ url := fmt.Sprintf("agile/1.0/board/%d/configuration", data.Options.BoardId)
+ boardConfiguration, err := data.ApiClient.Get(url, nil, nil)
+ if err != nil {
+ return err
+ }
+ bc := &BoardConfiguration{}
+ err = helper.UnmarshalResponse(boardConfiguration, bc)
+ if err != nil {
+ return err
+ }
+ filterId := bc.Filter.ID
+ logger.Info("collect board filter:%s", filterId)
+
+ // get board filter jql
+ url = fmt.Sprintf("api/2/filter/%s", filterId)
+ filterInfo, err := data.ApiClient.Get(url, nil, nil)
+ if err != nil {
+ return err
+ }
+ fi := &FilterInfo{}
+ err = helper.UnmarshalResponse(filterInfo, fi)
+ if err != nil {
+ return err
+ }
+ jql := fi.Jql
+ logger.Info("collect board filter jql:%s", jql)
+
+ // should not change
+ var record models.JiraBoard
+ err = db.First(&record, dal.Where("connection_id = ? AND board_id = ? ", data.Options.ConnectionId, data.Options.BoardId))
+ if err != nil {
+ return errors.Default.Wrap(err, fmt.Sprintf("error finding record in _tool_jira_boards table for connection_id:%d board_id:%d", data.Options.ConnectionId, data.Options.BoardId))
+ }
+
+ if record.Jql != jql {
+ return errors.Default.New(fmt.Sprintf("board filter jql has changed for connection_id:%d board_id:%d, please use fullSync mode!!!", data.Options.ConnectionId, data.Options.BoardId))
+ }
+
+ return nil
+}