You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by wa...@apache.org on 2022/10/17 06:20:08 UTC
[incubator-devlake] branch feat-plugin-zentao created (now 6a500469)
This is an automated email from the ASF dual-hosted git repository.
warren pushed a change to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
at 6a500469 feat:add zentao bugs
This branch includes the following new commits:
new d0852c82 feat(zentao): create new plugin
new 74f74a84 feat(zentao): create new plugin
new 1743a758 fix(zentao): update connection
new ef1c75fb update project collector
new 34298a21 feat:add zentao project extractor
new f0bd0762 fix(zentao): fix minor issues
new 47f3ecd6 feat(zentao): add execution
new 9919d22f feat(zentao): fix execution time
new c1172d00 feat(zentao): add zentao stories
new 8f3ff2c7 fix:apiurl&model error
new 23cb348d fix:restore code
new 6a500469 feat:add zentao bugs
The 12 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[incubator-devlake] 03/12: fix(zentao): update connection
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 1743a758f5ed302c8077fa42f489b34ce05b5467
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Sat Sep 10 15:35:59 2022 +0800
fix(zentao): update connection
---
plugins/zentao/models/archived/connection.go | 2 +-
plugins/zentao/models/migrationscripts/20220906_add_init_tables.go | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/plugins/zentao/models/archived/connection.go b/plugins/zentao/models/archived/connection.go
index 60d7178c..8a44237e 100644
--- a/plugins/zentao/models/archived/connection.go
+++ b/plugins/zentao/models/archived/connection.go
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package models
+package archived
import (
"github.com/apache/incubator-devlake/models/migrationscripts/archived"
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index 181bbc77..fa9f9684 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -19,19 +19,20 @@ package migrationscripts
import (
"context"
+ "github.com/apache/incubator-devlake/plugins/zentao/models/archived"
"gorm.io/gorm"
)
-type addInitTables struct {}
+type addInitTables struct{}
func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
return db.Migrator().AutoMigrate(
- // TODO add you models
+ archived.ZentaoConnection{},
)
}
func (*addInitTables) Version() uint64 {
- return 20220906000001
+ return 20220910000001
}
func (*addInitTables) Name() string {
[incubator-devlake] 11/12: fix:restore code
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 23cb348d90a3c46d69a7769d0c2c388d0a537532
Author: yuqiangabab <11...@qq.com>
AuthorDate: Sun Oct 2 11:26:48 2022 +0800
fix:restore code
---
plugins/zentao/impl/impl.go | 10 +++++-----
.../zentao/models/migrationscripts/20220906_add_init_tables.go | 6 +++---
plugins/zentao/tasks/task_data.go | 1 -
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index 9b6b8f0b..aaf3c922 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -52,11 +52,11 @@ func (plugin Zentao) Init(config *viper.Viper, logger core.Logger, db *gorm.DB)
func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
// TODO add your sub task here
return []core.SubTaskMeta{
- //tasks.CollectProjectMeta,
- //tasks.ExtractProjectsMeta,
- //tasks.CollectExecutionMeta,
- //tasks.ExtractExecutionsMeta,
- //tasks.ConvertExecutionsMeta,
+ tasks.CollectProjectMeta,
+ tasks.ExtractProjectsMeta,
+ tasks.CollectExecutionMeta,
+ tasks.ExtractExecutionsMeta,
+ tasks.ConvertExecutionsMeta,
tasks.CollectStoriesMeta,
tasks.ExtractStoriesMeta,
tasks.ConvertStoriesMeta,
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index 2213d937..3d51dcde 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -27,9 +27,9 @@ type addInitTables struct{}
func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
return db.Migrator().AutoMigrate(
- //archived.ZentaoConnection{},
- //archived.ZentaoProject{},
- //archived.ZentaoExecution{},
+ archived.ZentaoConnection{},
+ archived.ZentaoProject{},
+ archived.ZentaoExecution{},
archived.ZentaoStories{},
)
}
diff --git a/plugins/zentao/tasks/task_data.go b/plugins/zentao/tasks/task_data.go
index c522360e..a2d88f22 100644
--- a/plugins/zentao/tasks/task_data.go
+++ b/plugins/zentao/tasks/task_data.go
@@ -40,7 +40,6 @@ type ZentaoOptions struct {
ProjectId uint64
Tasks []string `json:"tasks,omitempty"`
Since string
- StoriesId uint64
}
type ZentaoTaskData struct {
[incubator-devlake] 09/12: feat(zentao): add zentao stories
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit c1172d0054115354e782618d1aa1fb6816453d2f
Author: yuqiangabab <11...@qq.com>
AuthorDate: Sun Sep 25 13:40:52 2022 +0800
feat(zentao): add zentao stories
---
plugins/zentao/impl/impl.go | 13 +-
plugins/zentao/models/archived/stories.go | 163 +++++++++++++++++++++
.../migrationscripts/20220906_add_init_tables.go | 3 +-
plugins/zentao/models/stories.go | 163 +++++++++++++++++++++
plugins/zentao/tasks/stories_collector.go | 77 ++++++++++
plugins/zentao/tasks/stories_convertor.go | 110 ++++++++++++++
plugins/zentao/tasks/stories_extractor.go | 65 ++++++++
plugins/zentao/tasks/task_data.go | 2 +
plugins/zentao/zentao.go | 2 +
9 files changed, 592 insertions(+), 6 deletions(-)
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index b4004753..9b6b8f0b 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -52,11 +52,14 @@ func (plugin Zentao) Init(config *viper.Viper, logger core.Logger, db *gorm.DB)
func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
// TODO add your sub task here
return []core.SubTaskMeta{
- tasks.CollectProjectMeta,
- tasks.ExtractProjectsMeta,
- tasks.CollectExecutionMeta,
- tasks.ExtractExecutionsMeta,
- tasks.ConvertExecutionsMeta,
+ //tasks.CollectProjectMeta,
+ //tasks.ExtractProjectsMeta,
+ //tasks.CollectExecutionMeta,
+ //tasks.ExtractExecutionsMeta,
+ //tasks.ConvertExecutionsMeta,
+ tasks.CollectStoriesMeta,
+ tasks.ExtractStoriesMeta,
+ tasks.ConvertStoriesMeta,
}
}
diff --git a/plugins/zentao/models/archived/stories.go b/plugins/zentao/models/archived/stories.go
new file mode 100644
index 00000000..cd608682
--- /dev/null
+++ b/plugins/zentao/models/archived/stories.go
@@ -0,0 +1,163 @@
+/*
+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 archived
+
+import (
+ "github.com/apache/incubator-devlake/models/migrationscripts/archived"
+ "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ZentaoStories struct {
+ archived.NoPKModel
+ ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
+ ID int `json:"id"gorm:"primaryKey;type:BIGINT NOT NULL"`
+ Vision string `json:"vision"`
+ Parent int `json:"parent"`
+ Product int `json:"product"`
+ Branch int `json:"branch"`
+ Module int `json:"module"`
+ Plan string `json:"plan"`
+ Source string `json:"source"`
+ SourceNote string `json:"sourceNote"`
+ FromBug int `json:"fromBug"`
+ Feedback int `json:"feedback"`
+ Title string `json:"title"`
+ Keywords string `json:"keywords"`
+ Type string `json:"type"`
+ Category string `json:"category"`
+ Pri int `json:"pri"`
+ Estimate int `json:"estimate"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Color string `json:"color"`
+ Stage string `json:"stage"`
+ StagedBy string `json:"stagedBy"`
+ //Mailto []interface{} `json:"mailto" gorm:"-:all"`
+ Lib int `json:"lib"`
+ FromStory int `json:"fromStory"`
+ FromVersion int `json:"fromVersion"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ ApprovedDate string `json:"approvedDate"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ ChangedBy string `json:"changedBy"`
+ ChangedDate string `json:"changedDate"`
+ ReviewedBy interface{} `json:"reviewedBy" gorm:"-:all"`
+ ReviewedDate *helper.Iso8601Time `json:"reviewedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
+ ClosedReason string `json:"closedReason"`
+ ActivatedDate string `json:"activatedDate"`
+ ToBug int `json:"toBug"`
+ ChildStories string `json:"childStories"`
+ LinkStories string `json:"linkStories"`
+ LinkRequirements string `json:"linkRequirements"`
+ DuplicateStory int `json:"duplicateStory"`
+ Version int `json:"version"`
+ StoryChanged string `json:"storyChanged"`
+ FeedbackBy string `json:"feedbackBy"`
+ NotifyEmail string `json:"notifyEmail"`
+ URChanged string `json:"URChanged"`
+ Deleted bool `json:"deleted"`
+ Spec string `json:"spec"`
+ Verify string `json:"verify"`
+ Executions Executions `json:"executions" gorm:"-:all"`
+ Tasks []Tasks `json:"tasks" gorm:"-:all"`
+ //Stages []interface{} `json:"stages" gorm:"-:all"`
+ PlanTitle []string `json:"planTitle" gorm:"-:all"`
+ //Children []interface{} `json:"children" gorm:"-:all"`
+ //Files []interface{} `json:"files" gorm:"-:all"`
+ ProductName string `json:"productName"`
+ ProductStatus string `json:"productStatus"`
+ ModuleTitle string `json:"moduleTitle"`
+ Bugs []Bugs `json:"bugs" gorm:"-:all"`
+ Cases []Cases `json:"cases" gorm:"-:all"`
+ //Requirements []interface{} `json:"requirements" gorm:"-:all"`
+ Actions []Actions `json:"actions" gorm:"-:all"`
+ PreAndNext `json:"preAndNext"`
+}
+type Executions struct {
+ Num1 struct {
+ Project int `json:"project"`
+ Name string `json:"name"`
+ Status string `json:"status"`
+ Type string `json:"type"`
+ } `json:"1"`
+}
+type Tasks struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Status string `json:"status"`
+ AssignedTo struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+ } `json:"assignedTo"`
+}
+type Bugs struct {
+ ID int `json:"id"`
+ Title string `json:"title"`
+ Status string `json:"status"`
+ Pri int `json:"pri"`
+ Severity int `json:"severity"`
+}
+type Cases struct {
+ ID int `json:"id"`
+ Title string `json:"title"`
+ Pri int `json:"pri"`
+ Status string `json:"status"`
+}
+
+type Actions struct {
+ ID int `json:"id"`
+ ObjectType string `json:"objectType"`
+ ObjectID int `json:"objectID"`
+ Product string `json:"product"`
+ Project int `json:"project"`
+ Execution int `json:"execution"`
+ Actor string `json:"actor"`
+ Action string `json:"action"`
+ Date string `json:"date"`
+ Comment string `json:"comment"`
+ Extra string `json:"extra"`
+ Read string `json:"read"`
+ Vision string `json:"vision"`
+ Efforted int `json:"efforted"`
+ //History []interface{} `json:"history"`
+ Desc string `json:"desc"`
+}
+type AssignedTo struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type PreAndNext struct {
+ Pre string `json:"pre"`
+ Next string `json:"next"`
+}
+
+func (ZentaoStories) TableName() string {
+ return "_tool_zentao_stories"
+}
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index 6635dda3..2213d937 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -29,7 +29,8 @@ func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
return db.Migrator().AutoMigrate(
//archived.ZentaoConnection{},
//archived.ZentaoProject{},
- archived.ZentaoExecution{},
+ //archived.ZentaoExecution{},
+ archived.ZentaoStories{},
)
}
diff --git a/plugins/zentao/models/stories.go b/plugins/zentao/models/stories.go
new file mode 100644
index 00000000..be198bbf
--- /dev/null
+++ b/plugins/zentao/models/stories.go
@@ -0,0 +1,163 @@
+/*
+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 models
+
+import (
+ "github.com/apache/incubator-devlake/models/common"
+ "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ZentaoStories struct {
+ common.NoPKModel
+ ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
+ ID int `json:"id"gorm:"primaryKey;type:BIGINT NOT NULL"`
+ Vision string `json:"vision"`
+ Parent int `json:"parent"`
+ Product int `json:"product"`
+ Branch int `json:"branch"`
+ Module int `json:"module"`
+ Plan string `json:"plan"`
+ Source string `json:"source"`
+ SourceNote string `json:"sourceNote"`
+ FromBug int `json:"fromBug"`
+ Feedback int `json:"feedback"`
+ Title string `json:"title"`
+ Keywords string `json:"keywords"`
+ Type string `json:"type"`
+ Category string `json:"category"`
+ Pri int `json:"pri"`
+ Estimate int `json:"estimate"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Color string `json:"color"`
+ Stage string `json:"stage"`
+ StagedBy string `json:"stagedBy"`
+ //Mailto []interface{} `json:"mailto" gorm:"-:all"`
+ Lib int `json:"lib"`
+ FromStory int `json:"fromStory"`
+ FromVersion int `json:"fromVersion"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ ApprovedDate string `json:"approvedDate"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ ChangedBy string `json:"changedBy"`
+ ChangedDate string `json:"changedDate"`
+ ReviewedBy interface{} `json:"reviewedBy" gorm:"-:all"`
+ ReviewedDate *helper.Iso8601Time `json:"reviewedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
+ ClosedReason string `json:"closedReason"`
+ ActivatedDate string `json:"activatedDate"`
+ ToBug int `json:"toBug"`
+ ChildStories string `json:"childStories"`
+ LinkStories string `json:"linkStories"`
+ LinkRequirements string `json:"linkRequirements"`
+ DuplicateStory int `json:"duplicateStory"`
+ Version int `json:"version"`
+ StoryChanged string `json:"storyChanged"`
+ FeedbackBy string `json:"feedbackBy"`
+ NotifyEmail string `json:"notifyEmail"`
+ URChanged string `json:"URChanged"`
+ Deleted bool `json:"deleted"`
+ Spec string `json:"spec"`
+ Verify string `json:"verify"`
+ Executions Executions `json:"executions" gorm:"-:all"`
+ Tasks []Tasks `json:"tasks" gorm:"-:all"`
+ //Stages []interface{} `json:"stages" gorm:"-:all"`
+ PlanTitle []string `json:"planTitle" gorm:"-:all"`
+ //Children []interface{} `json:"children" gorm:"-:all"`
+ //Files []interface{} `json:"files" gorm:"-:all"`
+ ProductName string `json:"productName"`
+ ProductStatus string `json:"productStatus"`
+ ModuleTitle string `json:"moduleTitle"`
+ Bugs []Bugs `json:"bugs" gorm:"-:all"`
+ Cases []Cases `json:"cases" gorm:"-:all"`
+ //Requirements []interface{} `json:"requirements" gorm:"-:all"`
+ Actions []Actions `json:"actions" gorm:"-:all"`
+ PreAndNext `json:"preAndNext"`
+}
+type Executions struct {
+ Num1 struct {
+ Project int `json:"project"`
+ Name string `json:"name"`
+ Status string `json:"status"`
+ Type string `json:"type"`
+ } `json:"1"`
+}
+type Tasks struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Type string `json:"type"`
+ Status string `json:"status"`
+ AssignedTo struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+ } `json:"assignedTo"`
+}
+type Bugs struct {
+ ID int `json:"id"`
+ Title string `json:"title"`
+ Status string `json:"status"`
+ Pri int `json:"pri"`
+ Severity int `json:"severity"`
+}
+type Cases struct {
+ ID int `json:"id"`
+ Title string `json:"title"`
+ Pri int `json:"pri"`
+ Status string `json:"status"`
+}
+
+type Actions struct {
+ ID int `json:"id"`
+ ObjectType string `json:"objectType"`
+ ObjectID int `json:"objectID"`
+ Product string `json:"product"`
+ Project int `json:"project"`
+ Execution int `json:"execution"`
+ Actor string `json:"actor"`
+ Action string `json:"action"`
+ Date string `json:"date"`
+ Comment string `json:"comment"`
+ Extra string `json:"extra"`
+ Read string `json:"read"`
+ Vision string `json:"vision"`
+ Efforted int `json:"efforted"`
+ //History []interface{} `json:"history"`
+ Desc string `json:"desc"`
+}
+type AssignedTo struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type PreAndNext struct {
+ Pre string `json:"pre"`
+ Next string `json:"next"`
+}
+
+func (ZentaoStories) TableName() string {
+ return "_tool_zentao_stories"
+}
diff --git a/plugins/zentao/tasks/stories_collector.go b/plugins/zentao/tasks/stories_collector.go
new file mode 100644
index 00000000..6ba58924
--- /dev/null
+++ b/plugins/zentao/tasks/stories_collector.go
@@ -0,0 +1,77 @@
+/*
+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 (
+ "encoding/json"
+ "fmt"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "io"
+ "net/http"
+ "net/url"
+)
+
+const RAW_STORIES_TABLE = "zentao_stories"
+
+var _ core.SubTaskEntryPoint = CollectExecution
+
+func CollectStories(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ StoriesId: data.Options.StoriesId,
+ },
+ Table: RAW_STORIES_TABLE,
+ },
+ ApiClient: data.ApiClient,
+ Incremental: false,
+ PageSize: 100,
+ // TODO write which api would you want request
+ UrlTemplate: "/stories/{{ .Params.StoriesId }}",
+ Query: func(reqData *helper.RequestData) (url.Values, error) {
+ query := url.Values{}
+ query.Set("page", fmt.Sprintf("%v", reqData.Pager.Page))
+ query.Set("limit", fmt.Sprintf("%v", reqData.Pager.Size))
+ return query, nil
+ },
+ GetTotalPages: GetTotalPagesFromResponse,
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
+ body, err := io.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ return []json.RawMessage{body}, nil
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ return collector.Execute()
+}
+
+var CollectStoriesMeta = core.SubTaskMeta{
+ Name: "CollectStories",
+ EntryPoint: CollectStories,
+ EnabledByDefault: true,
+ Description: "Collect Stories data from Zentao api",
+}
diff --git a/plugins/zentao/tasks/stories_convertor.go b/plugins/zentao/tasks/stories_convertor.go
new file mode 100644
index 00000000..a41a1868
--- /dev/null
+++ b/plugins/zentao/tasks/stories_convertor.go
@@ -0,0 +1,110 @@
+/*
+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 (
+ "github.com/apache/incubator-devlake/models/domainlayer"
+ "github.com/apache/incubator-devlake/models/domainlayer/didgen"
+ "github.com/apache/incubator-devlake/models/domainlayer/ticket"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/core/dal"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "reflect"
+)
+
+var _ core.SubTaskEntryPoint = ConvertExecutions
+
+var ConvertStoriesMeta = core.SubTaskMeta{
+ Name: "convertStories",
+ EntryPoint: ConvertStories,
+ EnabledByDefault: true,
+ Description: "convert Zentao stories",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ConvertStories(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ db := taskCtx.GetDal()
+ boardIdGen := didgen.NewDomainIdGenerator(&models.ZentaoStories{})
+ cursor, err := db.Cursor(
+ dal.From(&models.ZentaoStories{}),
+ dal.Where(`_tool_zentao_stories.id = ? and
+ _tool_zentao_stories.connection_id = ?`, data.Options.StoriesId, data.Options.ConnectionId),
+ )
+ if err != nil {
+ return err
+ }
+ defer cursor.Close()
+ convertor, err := helper.NewDataConverter(helper.DataConverterArgs{
+ InputRowType: reflect.TypeOf(models.ZentaoStories{}),
+ Input: cursor,
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ StoriesId: data.Options.StoriesId,
+ },
+ Table: RAW_STORIES_TABLE,
+ },
+ Convert: func(inputRow interface{}) ([]interface{}, error) {
+ toolStories := inputRow.(*models.ZentaoStories)
+
+ domainBoard := &ticket.Issue{
+ DomainEntity: domainlayer.DomainEntity{
+ Id: boardIdGen.Generate(toolStories.ConnectionId, toolStories.ID),
+ },
+ Url: "",
+ IconURL: "",
+ IssueKey: "",
+ Title: toolStories.Title,
+ Description: toolStories.Spec,
+ EpicKey: "",
+ Type: toolStories.Type,
+ Status: toolStories.Status,
+ OriginalStatus: "",
+ StoryPoint: 0,
+ ResolutionDate: nil,
+ CreatedDate: toolStories.OpenedDate.ToNullableTime(),
+ UpdatedDate: toolStories.LastEditedDate.ToNullableTime(),
+ LeadTimeMinutes: 0,
+ ParentIssueId: "",
+ Priority: "",
+ OriginalEstimateMinutes: 0,
+ TimeSpentMinutes: 0,
+ TimeRemainingMinutes: 0,
+ CreatorId: "",
+ CreatorName: toolStories.OpenedBy.OpenedByRealname,
+ AssigneeId: "",
+ AssigneeName: toolStories.AssignedTo.Realname,
+ Severity: "",
+ Component: "",
+ DeploymentId: "",
+ }
+
+ results := make([]interface{}, 0)
+ results = append(results, domainBoard)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return convertor.Execute()
+}
diff --git a/plugins/zentao/tasks/stories_extractor.go b/plugins/zentao/tasks/stories_extractor.go
new file mode 100644
index 00000000..aaadfb84
--- /dev/null
+++ b/plugins/zentao/tasks/stories_extractor.go
@@ -0,0 +1,65 @@
+/*
+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 (
+ "encoding/json"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+)
+
+var _ core.SubTaskEntryPoint = ExtractStories
+
+var ExtractStoriesMeta = core.SubTaskMeta{
+ Name: "extractStories",
+ EntryPoint: ExtractStories,
+ EnabledByDefault: true,
+ Description: "extract Zentao stories",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ExtractStories(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ StoriesId: data.Options.StoriesId,
+ },
+ Table: RAW_STORIES_TABLE,
+ },
+ Extract: func(row *helper.RawData) ([]interface{}, error) {
+ stories := &models.ZentaoStories{}
+ err := json.Unmarshal(row.Data, stories)
+ if err != nil {
+ return nil, err
+ }
+ stories.ConnectionId = data.Options.ConnectionId
+ results := make([]interface{}, 0)
+ results = append(results, stories)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return extractor.Execute()
+}
diff --git a/plugins/zentao/tasks/task_data.go b/plugins/zentao/tasks/task_data.go
index a2d88f22..ae51908f 100644
--- a/plugins/zentao/tasks/task_data.go
+++ b/plugins/zentao/tasks/task_data.go
@@ -27,6 +27,7 @@ type ZentaoApiParams struct {
ProductId uint64
ExecutionId uint64
ProjectId uint64
+ StoriesId uint64
}
type ZentaoOptions struct {
@@ -40,6 +41,7 @@ type ZentaoOptions struct {
ProjectId uint64
Tasks []string `json:"tasks,omitempty"`
Since string
+ StoriesId uint64
}
type ZentaoTaskData struct {
diff --git a/plugins/zentao/zentao.go b/plugins/zentao/zentao.go
index 32845c90..3768b5d9 100644
--- a/plugins/zentao/zentao.go
+++ b/plugins/zentao/zentao.go
@@ -34,6 +34,7 @@ func main() {
executionId := cmd.Flags().IntP("executionId", "e", 8, "execution id")
productId := cmd.Flags().IntP("productId", "o", 8, "product id")
projectId := cmd.Flags().IntP("projectId", "p", 8, "project id")
+ storiesId := cmd.Flags().IntP("storiesId", "s", 1, "stories id")
cmd.Run = func(cmd *cobra.Command, args []string) {
runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
@@ -41,6 +42,7 @@ func main() {
"executionId": *executionId,
"productId": *productId,
"projectId": *projectId,
+ "storiesId": *storiesId,
})
}
runner.RunCmd(cmd)
[incubator-devlake] 01/12: feat(zentao): create new plugin
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit d0852c8257b5e2ea3b54f7249d91983fd156c15f
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Tue Sep 6 18:03:04 2022 +0800
feat(zentao): create new plugin
Relate to #2961
---
plugins/zentao/api/blueprint.go | 69 ++++++++++
plugins/zentao/api/connection.go | 149 +++++++++++++++++++++
plugins/zentao/api/init.go | 39 ++++++
plugins/zentao/impl/impl.go | 124 +++++++++++++++++
plugins/zentao/models/archived/connection.go | 70 ++++++++++
plugins/zentao/models/connection.go | 51 +++++++
.../migrationscripts/20220906_add_init_tables.go | 39 ++++++
plugins/zentao/models/migrationscripts/register.go | 27 ++++
plugins/zentao/tasks/api_client.go | 92 +++++++++++++
plugins/zentao/tasks/project_collector.go | 78 +++++++++++
plugins/zentao/tasks/task_data.go | 61 +++++++++
plugins/zentao/zentao.go | 47 +++++++
12 files changed, 846 insertions(+)
diff --git a/plugins/zentao/api/blueprint.go b/plugins/zentao/api/blueprint.go
new file mode 100644
index 00000000..3fa0e25f
--- /dev/null
+++ b/plugins/zentao/api/blueprint.go
@@ -0,0 +1,69 @@
+/*
+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 (
+ "encoding/json"
+
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/tasks"
+)
+
+func MakePipelinePlan(subtaskMetas []core.SubTaskMeta, connectionId uint64, scope []*core.BlueprintScopeV100) (core.PipelinePlan, error) {
+ var err error
+ plan := make(core.PipelinePlan, len(scope))
+ for i, scopeElem := range scope {
+ taskOptions := make(map[string]interface{})
+ err = json.Unmarshal(scopeElem.Options, &taskOptions)
+ if err != nil {
+ return nil, err
+ }
+ taskOptions["connectionId"] = connectionId
+
+ //TODO Add transformation rules to task options
+
+ /*
+ var transformationRules tasks.TransformationRules
+ if len(scopeElem.Transformation) > 0 {
+ err = json.Unmarshal(scopeElem.Transformation, &transformationRules)
+ if err != nil {
+ return nil, err
+ }
+ }
+ */
+ //taskOptions["transformationRules"] = transformationRules
+ _, err := tasks.DecodeAndValidateTaskOptions(taskOptions)
+ if err != nil {
+ return nil, err
+ }
+ // subtasks
+ subtasks, err := helper.MakePipelinePlanSubtasks(subtaskMetas, scopeElem.Entities)
+ if err != nil {
+ return nil, err
+ }
+ plan[i] = core.PipelineStage{
+ {
+ Plugin: "zentao",
+ Subtasks: subtasks,
+ Options: taskOptions,
+ },
+ }
+ }
+ return plan, nil
+}
diff --git a/plugins/zentao/api/connection.go b/plugins/zentao/api/connection.go
new file mode 100644
index 00000000..2f8183d5
--- /dev/null
+++ b/plugins/zentao/api/connection.go
@@ -0,0 +1,149 @@
+/*
+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"
+ "github.com/apache/incubator-devlake/errors"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/feishu/apimodels"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "github.com/mitchellh/mapstructure"
+ "net/http"
+)
+
+//TODO Please modify the following code to fit your needs
+func TestConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ // process input
+ var params models.TestConnectionRequest
+ err := mapstructure.Decode(input.Body, ¶ms)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "could not decode request parameters", errors.AsUserMessage())
+ }
+ err = vld.Struct(params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "could not validate request parameters", errors.AsUserMessage())
+ }
+
+ authApiClient, err := helper.NewApiClient(context.TODO(), params.Endpoint, nil, 0, params.Proxy, basicRes)
+ if err != nil {
+ return nil, err
+ }
+
+ // request for access token
+ tokenReqBody := &apimodels.ApiAccessTokenRequest{
+ AppId: params.Username,
+ AppSecret: params.Password,
+ }
+ tokenRes, err := authApiClient.Post("/tokens", nil, tokenReqBody, nil)
+ if err != nil {
+ return nil, err
+ }
+ tokenResBody := &apimodels.ApiAccessTokenResponse{}
+ err = helper.UnmarshalResponse(tokenRes, tokenResBody)
+ if err != nil {
+ return nil, err
+ }
+ if tokenResBody.AppAccessToken == "" && tokenResBody.TenantAccessToken == "" {
+ return nil, errors.Default.New("failed to request access token")
+ }
+
+ // output
+ return nil, nil
+}
+
+//TODO Please modify the folowing code to adapt to your plugin
+/*
+POST /plugins/Zentao/connections
+{
+ "name": "Zentao data connection name",
+ "endpoint": "Zentao api endpoint, i.e. https://example.com",
+ "username": "username, usually should be email address",
+ "password": "Zentao api access token"
+}
+*/
+func PostConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ // update from request and save to database
+ connection := &models.ZentaoConnection{}
+ err := connectionHelper.Create(connection, input)
+ if err != nil {
+ return nil, err
+ }
+ return &core.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil
+}
+
+//TODO Please modify the folowing code to adapt to your plugin
+/*
+PATCH /plugins/Zentao/connections/:connectionId
+{
+ "name": "Zentao data connection name",
+ "endpoint": "Zentao api endpoint, i.e. https://example.com",
+ "username": "username, usually should be email address",
+ "password": "Zentao api access token"
+}
+*/
+func PatchConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ connection := &models.ZentaoConnection{}
+ err := connectionHelper.Patch(connection, input)
+ if err != nil {
+ return nil, err
+ }
+ return &core.ApiResourceOutput{Body: connection}, nil
+}
+
+/*
+DELETE /plugins/Zentao/connections/:connectionId
+*/
+func DeleteConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ connection := &models.ZentaoConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, err
+ }
+ err = connectionHelper.Delete(connection)
+ return &core.ApiResourceOutput{Body: connection}, err
+}
+
+/*
+GET /plugins/Zentao/connections
+*/
+func ListConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ var connections []models.ZentaoConnection
+ err := connectionHelper.List(&connections)
+ if err != nil {
+ return nil, err
+ }
+ return &core.ApiResourceOutput{Body: connections, Status: http.StatusOK}, nil
+}
+
+//TODO Please modify the folowing code to adapt to your plugin
+/*
+GET /plugins/Zentao/connections/:connectionId
+{
+ "name": "Zentao data connection name",
+ "endpoint": "Zentao api endpoint, i.e. https://merico.atlassian.net/rest",
+ "username": "username, usually should be email address",
+ "password": "Zentao api access token"
+}
+*/
+func GetConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ connection := &models.ZentaoConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ return &core.ApiResourceOutput{Body: connection}, err
+}
diff --git a/plugins/zentao/api/init.go b/plugins/zentao/api/init.go
new file mode 100644
index 00000000..6774e148
--- /dev/null
+++ b/plugins/zentao/api/init.go
@@ -0,0 +1,39 @@
+/*
+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 (
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/go-playground/validator/v10"
+ "github.com/spf13/viper"
+ "gorm.io/gorm"
+)
+
+var vld *validator.Validate
+var connectionHelper *helper.ConnectionApiHelper
+var basicRes core.BasicRes
+
+func Init(config *viper.Viper, logger core.Logger, database *gorm.DB) {
+ basicRes = helper.NewDefaultBasicRes(config, logger, database)
+ vld = validator.New()
+ connectionHelper = helper.NewConnectionHelper(
+ basicRes,
+ vld,
+ )
+}
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
new file mode 100644
index 00000000..cc81c226
--- /dev/null
+++ b/plugins/zentao/impl/impl.go
@@ -0,0 +1,124 @@
+/*
+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 impl
+
+import (
+ "fmt"
+ "github.com/apache/incubator-devlake/migration"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/zentao/api"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "github.com/apache/incubator-devlake/plugins/zentao/models/migrationscripts"
+ "github.com/apache/incubator-devlake/plugins/zentao/tasks"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/spf13/viper"
+ "gorm.io/gorm"
+)
+
+// make sure interface is implemented
+var _ core.PluginMeta = (*Zentao)(nil)
+var _ core.PluginInit = (*Zentao)(nil)
+var _ core.PluginTask = (*Zentao)(nil)
+var _ core.PluginApi = (*Zentao)(nil)
+var _ core.PluginBlueprintV100 = (*Zentao)(nil)
+var _ core.CloseablePluginTask = (*Zentao)(nil)
+
+
+
+type Zentao struct{}
+
+func (plugin Zentao) Description() string {
+ return "collect some Zentao data"
+}
+
+func (plugin Zentao) Init(config *viper.Viper, logger core.Logger, db *gorm.DB) error {
+ api.Init(config, logger, db)
+ return nil
+}
+
+func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
+ // TODO add your sub task here
+ return []core.SubTaskMeta{
+ tasks.CollectProjectMeta,
+ }
+}
+
+func (plugin Zentao) PrepareTaskData(taskCtx core.TaskContext, options map[string]interface{}) (interface{}, error) {
+ op, err := tasks.DecodeAndValidateTaskOptions(options)
+ if err != nil {
+ return nil, err
+ }
+ connectionHelper := helper.NewConnectionHelper(
+ taskCtx,
+ nil,
+ )
+ connection := &models.ZentaoConnection{}
+ err = connectionHelper.FirstById(connection, op.ConnectionId)
+ if err != nil {
+ return nil, fmt.Errorf("unable to get Zentao connection by the given connection ID: %v", err)
+ }
+
+ apiClient, err := tasks.NewZentaoApiClient(taskCtx, connection)
+ if err != nil {
+ return nil, fmt.Errorf("unable to get Zentao API client instance: %v", err)
+ }
+
+ return &tasks.ZentaoTaskData{
+ Options: op,
+ ApiClient: apiClient,
+ }, nil
+}
+
+// PkgPath information lost when compiled as plugin(.so)
+func (plugin Zentao) RootPkgPath() string {
+ return "github.com/apache/incubator-devlake/plugins/zentao"
+}
+
+func (plugin Zentao) MigrationScripts() []migration.Script {
+ return migrationscripts.All()
+}
+
+func (plugin Zentao) ApiResources() map[string]map[string]core.ApiResourceHandler {
+ return map[string]map[string]core.ApiResourceHandler{
+ "test": {
+ "POST": api.TestConnection,
+ },
+ "connections": {
+ "POST": api.PostConnections,
+ "GET": api.ListConnections,
+ },
+ "connections/:connectionId": {
+ "GET": api.GetConnection,
+ "PATCH": api.PatchConnection,
+ "DELETE": api.DeleteConnection,
+ },
+ }
+}
+
+func (plugin Zentao) MakePipelinePlan(connectionId uint64, scope []*core.BlueprintScopeV100) (core.PipelinePlan, error) {
+ return api.MakePipelinePlan(plugin.SubTaskMetas(), connectionId, scope)
+}
+
+func (plugin Zentao) Close(taskCtx core.TaskContext) error {
+ data, ok := taskCtx.GetData().(*tasks.ZentaoTaskData)
+ if !ok {
+ return fmt.Errorf("GetData failed when try to close %+v", taskCtx)
+ }
+ data.ApiClient.Release()
+ return nil
+}
diff --git a/plugins/zentao/models/archived/connection.go b/plugins/zentao/models/archived/connection.go
new file mode 100644
index 00000000..60d7178c
--- /dev/null
+++ b/plugins/zentao/models/archived/connection.go
@@ -0,0 +1,70 @@
+/*
+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 models
+
+import (
+ "github.com/apache/incubator-devlake/models/migrationscripts/archived"
+)
+
+//TODO Please modify the following code to fit your needs
+// This object conforms to what the frontend currently sends.
+type ZentaoConnection struct {
+ RestConnection `mapstructure:",squash"`
+ //TODO you may need to use helper.BasicAuth instead of helper.AccessToken
+ BasicAuth `mapstructure:",squash"`
+}
+
+type TestConnectionRequest struct {
+ Endpoint string `json:"endpoint"`
+ Proxy string `json:"proxy"`
+ BasicAuth `mapstructure:",squash"`
+}
+
+// This object conforms to what the frontend currently expects.
+type ZentaoResponse struct {
+ Name string `json:"name"`
+ ID int `json:"id"`
+ ZentaoConnection
+}
+
+// Using User because it requires authentication.
+type ApiUserResponse struct {
+ Id int
+ Name string `json:"name"`
+}
+
+func (ZentaoConnection) TableName() string {
+ return "_tool_zentao_connections"
+}
+
+type BasicAuth struct {
+ Username string `mapstructure:"username" validate:"required" json:"username"`
+ Password string `mapstructure:"password" validate:"required" json:"password"`
+}
+
+type RestConnection struct {
+ BaseConnection `mapstructure:",squash"`
+ Endpoint string `mapstructure:"endpoint" validate:"required" json:"endpoint"`
+ Proxy string `mapstructure:"proxy" json:"proxy"`
+ RateLimitPerHour int `comment:"api request rate limt per hour" json:"rateLimit"`
+}
+
+type BaseConnection struct {
+ Name string `gorm:"type:varchar(100);uniqueIndex" json:"name" validate:"required"`
+ archived.Model
+}
diff --git a/plugins/zentao/models/connection.go b/plugins/zentao/models/connection.go
new file mode 100644
index 00000000..6140d7f4
--- /dev/null
+++ b/plugins/zentao/models/connection.go
@@ -0,0 +1,51 @@
+/*
+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 models
+
+import "github.com/apache/incubator-devlake/plugins/helper"
+
+//TODO Please modify the following code to fit your needs
+// This object conforms to what the frontend currently sends.
+type ZentaoConnection struct {
+ helper.RestConnection `mapstructure:",squash"`
+ //TODO you may need to use helper.BasicAuth instead of helper.AccessToken
+ helper.BasicAuth `mapstructure:",squash"`
+}
+
+type TestConnectionRequest struct {
+ Endpoint string `json:"endpoint"`
+ Proxy string `json:"proxy"`
+ helper.BasicAuth `mapstructure:",squash"`
+}
+
+// This object conforms to what the frontend currently expects.
+type ZentaoResponse struct {
+ Name string `json:"name"`
+ ID int `json:"id"`
+ ZentaoConnection
+}
+
+// Using User because it requires authentication.
+type ApiUserResponse struct {
+ Id int
+ Name string `json:"name"`
+}
+
+func (ZentaoConnection) TableName() string {
+ return "_tool_zentao_connections"
+}
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
new file mode 100644
index 00000000..181bbc77
--- /dev/null
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -0,0 +1,39 @@
+/*
+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 (
+ "context"
+ "gorm.io/gorm"
+)
+
+type addInitTables struct {}
+
+func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
+ return db.Migrator().AutoMigrate(
+ // TODO add you models
+ )
+}
+
+func (*addInitTables) Version() uint64 {
+ return 20220906000001
+}
+
+func (*addInitTables) Name() string {
+ return "zentao init schemas"
+}
diff --git a/plugins/zentao/models/migrationscripts/register.go b/plugins/zentao/models/migrationscripts/register.go
new file mode 100644
index 00000000..92e20c01
--- /dev/null
+++ b/plugins/zentao/models/migrationscripts/register.go
@@ -0,0 +1,27 @@
+/*
+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/migration"
+
+// All return all the migration scripts
+func All() []migration.Script {
+ return []migration.Script{
+ new(addInitTables),
+ }
+}
diff --git a/plugins/zentao/tasks/api_client.go b/plugins/zentao/tasks/api_client.go
new file mode 100644
index 00000000..62d2d954
--- /dev/null
+++ b/plugins/zentao/tasks/api_client.go
@@ -0,0 +1,92 @@
+/*
+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/errors"
+ "github.com/apache/incubator-devlake/plugins/feishu/apimodels"
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+)
+
+func NewZentaoApiClient(taskCtx core.TaskContext, connection *models.ZentaoConnection) (*helper.ApiAsyncClient, error) {
+ authApiClient, err := helper.NewApiClient(taskCtx.GetContext(), connection.Endpoint, nil, 0, connection.Proxy, taskCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ // request for access token
+ tokenReqBody := &apimodels.ApiAccessTokenRequest{
+ AppId: connection.Username,
+ AppSecret: connection.Password,
+ }
+ tokenRes, err := authApiClient.Post("/tokens", nil, tokenReqBody, nil)
+ if err != nil {
+ return nil, err
+ }
+ tokenResBody := &apimodels.ApiAccessTokenResponse{}
+ err = helper.UnmarshalResponse(tokenRes, tokenResBody)
+ if err != nil {
+ return nil, err
+ }
+ if tokenResBody.AppAccessToken == "" && tokenResBody.TenantAccessToken == "" {
+ return nil, errors.Default.New("failed to request access token")
+ }
+ // real request apiClient
+ apiClient, err := helper.NewApiClient(taskCtx.GetContext(), connection.Endpoint, nil, 0, connection.Proxy, taskCtx)
+ if err != nil {
+ return nil, err
+ }
+ // set token
+ apiClient.SetHeaders(map[string]string{
+ "Token": fmt.Sprintf("%v", tokenResBody.TenantAccessToken),
+ })
+
+ // create rate limit calculator
+ rateLimiter := &helper.ApiRateLimitCalculator{
+ UserRateLimitPerHour: connection.RateLimitPerHour,
+ DynamicRateLimit: func(res *http.Response) (int, time.Duration, error) {
+ rateLimitHeader := res.Header.Get("RateLimit-Limit")
+ if rateLimitHeader == "" {
+ // use default
+ return 0, 0, nil
+ }
+ rateLimit, err := strconv.Atoi(rateLimitHeader)
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to parse RateLimit-Limit header: %w", err)
+ }
+ // seems like {{ .plugin-ame }} rate limit is on minute basis
+ return rateLimit, 1 * time.Minute, nil
+ },
+ }
+ asyncApiClient, err := helper.CreateAsyncApiClient(
+ taskCtx,
+ apiClient,
+ rateLimiter,
+ )
+ if err != nil {
+ return nil, err
+ }
+ return asyncApiClient, nil
+}
diff --git a/plugins/zentao/tasks/project_collector.go b/plugins/zentao/tasks/project_collector.go
new file mode 100644
index 00000000..7af9dc2c
--- /dev/null
+++ b/plugins/zentao/tasks/project_collector.go
@@ -0,0 +1,78 @@
+/*
+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 (
+ "encoding/json"
+ "fmt"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "net/http"
+ "net/url"
+)
+
+const RAW_PROJECT_TABLE = "zentao_project"
+
+var _ core.SubTaskEntryPoint = CollectProject
+
+func CollectProject(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ iterator, err := helper.NewDateIterator(365)
+ if err != nil {
+ return err
+ }
+
+ collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{},
+ Table: RAW_PROJECT_TABLE,
+ },
+ ApiClient: data.ApiClient,
+ Incremental: false,
+ Input: iterator,
+ PageSize: 100,
+ // TODO write which api would you want request
+ UrlTemplate: "projects",
+ Query: func(reqData *helper.RequestData) (url.Values, error) {
+ query := url.Values{}
+ query.Set("page", fmt.Sprintf("%v", reqData.Pager.Page))
+ query.Set("limit", fmt.Sprintf("%v", reqData.Pager.Size))
+ return query, nil
+ },
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
+ var data struct {
+ Projects []json.RawMessage `json:"data"`
+ }
+ err = helper.UnmarshalResponse(res, &data)
+ return data.Projects, err
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ return collector.Execute()
+}
+
+var CollectProjectMeta = core.SubTaskMeta{
+ Name: "CollectProject",
+ EntryPoint: CollectProject,
+ EnabledByDefault: true,
+ Description: "Collect Project data from Zentao api",
+}
diff --git a/plugins/zentao/tasks/task_data.go b/plugins/zentao/tasks/task_data.go
new file mode 100644
index 00000000..a2d88f22
--- /dev/null
+++ b/plugins/zentao/tasks/task_data.go
@@ -0,0 +1,61 @@
+/*
+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/plugins/helper"
+ "github.com/mitchellh/mapstructure"
+)
+
+type ZentaoApiParams struct {
+ ProductId uint64
+ ExecutionId uint64
+ ProjectId uint64
+}
+
+type ZentaoOptions struct {
+ // TODO add some custom options here if necessary
+ // options means some custom params required by plugin running.
+ // Such As How many rows do your want
+ // You can use it in sub tasks and you need pass it in main.go and pipelines.
+ ConnectionId uint64 `json:"connectionId"`
+ ProductId uint64
+ ExecutionId uint64
+ ProjectId uint64
+ Tasks []string `json:"tasks,omitempty"`
+ Since string
+}
+
+type ZentaoTaskData struct {
+ Options *ZentaoOptions
+ ApiClient *helper.ApiAsyncClient
+}
+
+func DecodeAndValidateTaskOptions(options map[string]interface{}) (*ZentaoOptions, error) {
+ var op ZentaoOptions
+ err := mapstructure.Decode(options, &op)
+ if err != nil {
+ return nil, err
+ }
+
+ if op.ConnectionId == 0 {
+ return nil, fmt.Errorf("connectionId is invalid")
+ }
+ return &op, nil
+}
diff --git a/plugins/zentao/zentao.go b/plugins/zentao/zentao.go
new file mode 100644
index 00000000..32845c90
--- /dev/null
+++ b/plugins/zentao/zentao.go
@@ -0,0 +1,47 @@
+/*
+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 main
+
+import (
+ "github.com/apache/incubator-devlake/plugins/Zentao/impl"
+ "github.com/apache/incubator-devlake/runner"
+ "github.com/spf13/cobra"
+)
+
+// Export a variable named PluginEntry for Framework to search and load
+var PluginEntry impl.Zentao //nolint
+
+// standalone mode for debugging
+func main() {
+ cmd := &cobra.Command{Use: "zentao"}
+
+ connectionId := cmd.Flags().Uint64P("connectionId", "c", 0, "zentao connection id")
+ executionId := cmd.Flags().IntP("executionId", "e", 8, "execution id")
+ productId := cmd.Flags().IntP("productId", "o", 8, "product id")
+ projectId := cmd.Flags().IntP("projectId", "p", 8, "project id")
+
+ cmd.Run = func(cmd *cobra.Command, args []string) {
+ runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+ "connectionId": *connectionId,
+ "executionId": *executionId,
+ "productId": *productId,
+ "projectId": *projectId,
+ })
+ }
+ runner.RunCmd(cmd)
+}
[incubator-devlake] 12/12: feat:add zentao bugs
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 6a500469fbd5df7d2b5c8abbf6a6bc078c6ac272
Author: yuqiangabab <11...@qq.com>
AuthorDate: Wed Oct 5 12:57:25 2022 +0800
feat:add zentao bugs
---
plugins/zentao/impl/impl.go | 3 +
plugins/zentao/models/archived/bug.go | 112 +++++++++++++++++++++
plugins/zentao/models/bug.go | 112 +++++++++++++++++++++
.../migrationscripts/20220906_add_init_tables.go | 1 +
plugins/zentao/tasks/bug_collector.go | 84 ++++++++++++++++
plugins/zentao/tasks/bug_convertor.go | 110 ++++++++++++++++++++
plugins/zentao/tasks/bug_extractor.go | 67 ++++++++++++
7 files changed, 489 insertions(+)
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index aaf3c922..8091e898 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -60,6 +60,9 @@ func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
tasks.CollectStoriesMeta,
tasks.ExtractStoriesMeta,
tasks.ConvertStoriesMeta,
+ tasks.CollectBugMeta,
+ tasks.ExtractBugMeta,
+ tasks.ConvertBugMeta,
}
}
diff --git a/plugins/zentao/models/archived/bug.go b/plugins/zentao/models/archived/bug.go
new file mode 100644
index 00000000..3743b761
--- /dev/null
+++ b/plugins/zentao/models/archived/bug.go
@@ -0,0 +1,112 @@
+/*
+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 archived
+
+import (
+ "github.com/apache/incubator-devlake/models/migrationscripts/archived"
+ "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ZentaoBug struct {
+ archived.NoPKModel
+ ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
+ ID int `json:"id" gorm:"primaryKey"`
+ Project int `json:"project"`
+ Product int `json:"product"`
+ Injection int `json:"injection"`
+ Identify int `json:"identify"`
+ Branch int `json:"branch"`
+ Module int `json:"module"`
+ Execution int `json:"execution"`
+ Plan int `json:"plan"`
+ Story int `json:"story"`
+ StoryVersion int `json:"storyVersion"`
+ Task int `json:"task"`
+ ToTask int `json:"toTask"`
+ ToStory int `json:"toStory"`
+ Title string `json:"title"`
+ Keywords string `json:"keywords"`
+ Severity int `json:"severity"`
+ Pri int `json:"pri"`
+ Type string `json:"type"`
+ Os string `json:"os"`
+ Browser string `json:"browser"`
+ Hardware string `json:"hardware"`
+ Found string `json:"found"`
+ Steps string `json:"steps"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Color string `json:"color"`
+ Confirmed int `json:"confirmed"`
+ ActivatedCount int `json:"activatedCount"`
+ ActivatedDate string `json:"activatedDate"`
+ FeedbackBy string `json:"feedbackBy"`
+ NotifyEmail string `json:"notifyEmail"`
+ Mailto []Mailto `json:"mailto" gorm:"-:all"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ OpenedBuild string `json:"openedBuild"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ Deadline string `json:"deadline"`
+ ResolvedBy `json:"resolvedBy"`
+ Resolution string `json:"resolution"`
+ ResolvedBuild string `json:"resolvedBuild"`
+ ResolvedDate *helper.Iso8601Time `json:"resolvedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
+ DuplicateBug int `json:"duplicateBug"`
+ LinkBug string `json:"linkBug"`
+ Case int `json:"case"`
+ CaseVersion int `json:"caseVersion"`
+ Feedback int `json:"feedback"`
+ Result int `json:"result"`
+ Repo int `json:"repo"`
+ Mr int `json:"mr"`
+ Entry string `json:"entry"`
+ Lines string `json:"lines"`
+ V1 string `json:"v1"`
+ V2 string `json:"v2"`
+ RepoType string `json:"repoType"`
+ IssueKey string `json:"issueKey"`
+ Testtask int `json:"testtask"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ Deleted bool `json:"deleted"`
+ PriOrder string `json:"priOrder"`
+ SeverityOrder int `json:"severityOrder"`
+ Needconfirm bool `json:"needconfirm"`
+ StatusName string `json:"statusName"`
+ ProductStatus string `json:"productStatus"`
+}
+type ResolvedBy struct {
+ ResolvedByID int `json:"id"`
+ ResolvedByAccount string `json:"account"`
+ ResolvedByAvatar string `json:"avatar"`
+ ResolvedByRealname string `json:"realname"`
+}
+type Mailto struct {
+ MailtoID int `json:"id"`
+ MailtoAccount string `json:"account"`
+ MailtoAvatar string `json:"avatar"`
+ MailtoRealname string `json:"realname"`
+}
+
+func (ZentaoBug) TableName() string {
+ return "_tool_zentao_bugs"
+}
diff --git a/plugins/zentao/models/bug.go b/plugins/zentao/models/bug.go
new file mode 100644
index 00000000..c081ed9c
--- /dev/null
+++ b/plugins/zentao/models/bug.go
@@ -0,0 +1,112 @@
+/*
+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 models
+
+import (
+ "github.com/apache/incubator-devlake/models/common"
+ "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+type ZentaoBug struct {
+ common.NoPKModel
+ ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
+ ID int `json:"id" gorm:"primaryKey"`
+ Project int `json:"project"`
+ Product int `json:"product"`
+ Injection int `json:"injection"`
+ Identify int `json:"identify"`
+ Branch int `json:"branch"`
+ Module int `json:"module"`
+ Execution int `json:"execution"`
+ Plan int `json:"plan"`
+ Story int `json:"story"`
+ StoryVersion int `json:"storyVersion"`
+ Task int `json:"task"`
+ ToTask int `json:"toTask"`
+ ToStory int `json:"toStory"`
+ Title string `json:"title"`
+ Keywords string `json:"keywords"`
+ Severity int `json:"severity"`
+ Pri int `json:"pri"`
+ Type string `json:"type"`
+ Os string `json:"os"`
+ Browser string `json:"browser"`
+ Hardware string `json:"hardware"`
+ Found string `json:"found"`
+ Steps string `json:"steps"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Color string `json:"color"`
+ Confirmed int `json:"confirmed"`
+ ActivatedCount int `json:"activatedCount"`
+ ActivatedDate string `json:"activatedDate"`
+ FeedbackBy string `json:"feedbackBy"`
+ NotifyEmail string `json:"notifyEmail"`
+ Mailto []Mailto `json:"mailto" gorm:"-:all"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ OpenedBuild string `json:"openedBuild"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ Deadline string `json:"deadline"`
+ ResolvedBy `json:"resolvedBy"`
+ Resolution string `json:"resolution"`
+ ResolvedBuild string `json:"resolvedBuild"`
+ ResolvedDate *helper.Iso8601Time `json:"resolvedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
+ DuplicateBug int `json:"duplicateBug"`
+ LinkBug string `json:"linkBug"`
+ Case int `json:"case"`
+ CaseVersion int `json:"caseVersion"`
+ Feedback int `json:"feedback"`
+ Result int `json:"result"`
+ Repo int `json:"repo"`
+ Mr int `json:"mr"`
+ Entry string `json:"entry"`
+ Lines string `json:"lines"`
+ V1 string `json:"v1"`
+ V2 string `json:"v2"`
+ RepoType string `json:"repoType"`
+ IssueKey string `json:"issueKey"`
+ Testtask int `json:"testtask"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ Deleted bool `json:"deleted"`
+ PriOrder string `json:"priOrder"`
+ SeverityOrder int `json:"severityOrder"`
+ Needconfirm bool `json:"needconfirm"`
+ StatusName string `json:"statusName"`
+ ProductStatus string `json:"productStatus"`
+}
+type ResolvedBy struct {
+ ResolvedByID int `json:"id"`
+ ResolvedByAccount string `json:"account"`
+ ResolvedByAvatar string `json:"avatar"`
+ ResolvedByRealname string `json:"realname"`
+}
+type Mailto struct {
+ MailtoID int `json:"id"`
+ MailtoAccount string `json:"account"`
+ MailtoAvatar string `json:"avatar"`
+ MailtoRealname string `json:"realname"`
+}
+
+func (ZentaoBug) TableName() string {
+ return "_tool_zentao_bugs"
+}
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index 3d51dcde..ade33e29 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -31,6 +31,7 @@ func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
archived.ZentaoProject{},
archived.ZentaoExecution{},
archived.ZentaoStories{},
+ archived.ZentaoBug{},
)
}
diff --git a/plugins/zentao/tasks/bug_collector.go b/plugins/zentao/tasks/bug_collector.go
new file mode 100644
index 00000000..d47c3bdd
--- /dev/null
+++ b/plugins/zentao/tasks/bug_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 (
+ "encoding/json"
+ "fmt"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "io"
+ "net/http"
+ "net/url"
+)
+
+const RAW_BUG_TABLE = "zentao_bug"
+
+var _ core.SubTaskEntryPoint = CollectExecution
+
+func CollectBug(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_BUG_TABLE,
+ },
+ ApiClient: data.ApiClient,
+ Incremental: false,
+ PageSize: 100,
+ // TODO write which api would you want request
+ UrlTemplate: "/products/{{ .Params.ProductId }}/bugs",
+ Query: func(reqData *helper.RequestData) (url.Values, error) {
+ query := url.Values{}
+ query.Set("page", fmt.Sprintf("%v", reqData.Pager.Page))
+ query.Set("limit", fmt.Sprintf("%v", reqData.Pager.Size))
+ return query, nil
+ },
+ GetTotalPages: GetTotalPagesFromResponse,
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
+ var data struct {
+ Bugs []json.RawMessage `json:"bugs"`
+ }
+ body, err := io.ReadAll(res.Body)
+ json.Unmarshal(body, &data)
+ res.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ return data.Bugs, nil
+ //return []json.RawMessage{body}, nil
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ return collector.Execute()
+}
+
+var CollectBugMeta = core.SubTaskMeta{
+ Name: "CollectBug",
+ EntryPoint: CollectBug,
+ EnabledByDefault: true,
+ Description: "Collect Bug data from Zentao api",
+}
diff --git a/plugins/zentao/tasks/bug_convertor.go b/plugins/zentao/tasks/bug_convertor.go
new file mode 100644
index 00000000..beb99cfd
--- /dev/null
+++ b/plugins/zentao/tasks/bug_convertor.go
@@ -0,0 +1,110 @@
+/*
+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 (
+ "github.com/apache/incubator-devlake/models/domainlayer"
+ "github.com/apache/incubator-devlake/models/domainlayer/didgen"
+ "github.com/apache/incubator-devlake/models/domainlayer/ticket"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/core/dal"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "reflect"
+)
+
+var _ core.SubTaskEntryPoint = ConvertExecutions
+
+var ConvertBugMeta = core.SubTaskMeta{
+ Name: "convertBug",
+ EntryPoint: ConvertBug,
+ EnabledByDefault: true,
+ Description: "convert Zentao bug",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ConvertBug(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ db := taskCtx.GetDal()
+ boardIdGen := didgen.NewDomainIdGenerator(&models.ZentaoBug{})
+ cursor, err := db.Cursor(
+ dal.From(&models.ZentaoBug{}),
+ dal.Where(`_tool_zentao_bugs.product = ? and
+ _tool_zentao_bugs.connection_id = ?`, data.Options.ProductId, data.Options.ConnectionId),
+ )
+ if err != nil {
+ return err
+ }
+ defer cursor.Close()
+ convertor, err := helper.NewDataConverter(helper.DataConverterArgs{
+ InputRowType: reflect.TypeOf(models.ZentaoBug{}),
+ Input: cursor,
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_BUG_TABLE,
+ },
+ Convert: func(inputRow interface{}) ([]interface{}, error) {
+ toolBug := inputRow.(*models.ZentaoBug)
+ domainBoard := &ticket.Issue{
+ DomainEntity: domainlayer.DomainEntity{
+ Id: boardIdGen.Generate(toolBug.ConnectionId, toolBug.ID),
+ },
+ Url: "",
+ IconURL: "",
+ IssueKey: toolBug.IssueKey,
+ Title: toolBug.Title,
+ Description: "",
+ EpicKey: "",
+ Type: toolBug.Type,
+ Status: toolBug.Status,
+ OriginalStatus: "",
+ StoryPoint: 0,
+ ResolutionDate: toolBug.ResolvedDate.ToNullableTime(),
+ CreatedDate: toolBug.OpenedDate.ToNullableTime(),
+ UpdatedDate: toolBug.LastEditedDate.ToNullableTime(),
+ LeadTimeMinutes: 0,
+ ParentIssueId: "",
+ Priority: string(toolBug.Pri),
+ OriginalEstimateMinutes: 0,
+ TimeSpentMinutes: 0,
+ TimeRemainingMinutes: 0,
+ CreatorId: string(toolBug.OpenedBy.OpenedByID),
+ CreatorName: toolBug.OpenedBy.OpenedByRealname,
+ AssigneeId: string(toolBug.AssignedTo.ID),
+ AssigneeName: toolBug.AssignedTo.Realname,
+ Severity: string(toolBug.Severity),
+ Component: "",
+ DeploymentId: "",
+ }
+ results := make([]interface{}, 0)
+ results = append(results, domainBoard)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return convertor.Execute()
+}
diff --git a/plugins/zentao/tasks/bug_extractor.go b/plugins/zentao/tasks/bug_extractor.go
new file mode 100644
index 00000000..4dbb3205
--- /dev/null
+++ b/plugins/zentao/tasks/bug_extractor.go
@@ -0,0 +1,67 @@
+/*
+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 (
+ "encoding/json"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+)
+
+var _ core.SubTaskEntryPoint = ExtractBug
+
+var ExtractBugMeta = core.SubTaskMeta{
+ Name: "extractBug",
+ EntryPoint: ExtractBug,
+ EnabledByDefault: true,
+ Description: "extract Zentao bug",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ExtractBug(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_BUG_TABLE,
+ },
+ Extract: func(row *helper.RawData) ([]interface{}, error) {
+ bug := &models.ZentaoBug{}
+ err := json.Unmarshal(row.Data, bug)
+ if err != nil {
+ return nil, err
+ }
+ bug.ConnectionId = data.Options.ConnectionId
+ results := make([]interface{}, 0)
+ results = append(results, bug)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return extractor.Execute()
+}
[incubator-devlake] 04/12: update project collector
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit ef1c75fb7ec98d0e958ea19a24ca2c90cac49b1b
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Sat Sep 10 15:50:00 2022 +0800
update project collector
---
plugins/zentao/tasks/api_client.go | 4 ++++
plugins/zentao/tasks/project_collector.go | 11 +++-------
plugins/zentao/tasks/shared.go | 34 +++++++++++++++++++++++++++++++
3 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/plugins/zentao/tasks/api_client.go b/plugins/zentao/tasks/api_client.go
index 17d490fb..e5105ded 100644
--- a/plugins/zentao/tasks/api_client.go
+++ b/plugins/zentao/tasks/api_client.go
@@ -89,3 +89,7 @@ func NewZentaoApiClient(taskCtx core.TaskContext, connection *models.ZentaoConne
}
return asyncApiClient, nil
}
+
+type ZentaoPagination struct {
+ Page int `json:"page"`
+}
diff --git a/plugins/zentao/tasks/project_collector.go b/plugins/zentao/tasks/project_collector.go
index 7af9dc2c..1aafec69 100644
--- a/plugins/zentao/tasks/project_collector.go
+++ b/plugins/zentao/tasks/project_collector.go
@@ -32,11 +32,6 @@ var _ core.SubTaskEntryPoint = CollectProject
func CollectProject(taskCtx core.SubTaskContext) error {
data := taskCtx.GetData().(*ZentaoTaskData)
- iterator, err := helper.NewDateIterator(365)
- if err != nil {
- return err
- }
-
collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
@@ -45,7 +40,6 @@ func CollectProject(taskCtx core.SubTaskContext) error {
},
ApiClient: data.ApiClient,
Incremental: false,
- Input: iterator,
PageSize: 100,
// TODO write which api would you want request
UrlTemplate: "projects",
@@ -55,11 +49,12 @@ func CollectProject(taskCtx core.SubTaskContext) error {
query.Set("limit", fmt.Sprintf("%v", reqData.Pager.Size))
return query, nil
},
+ GetTotalPages: GetTotalPagesFromResponse,
ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
var data struct {
- Projects []json.RawMessage `json:"data"`
+ Projects []json.RawMessage `json:"projects"`
}
- err = helper.UnmarshalResponse(res, &data)
+ err := helper.UnmarshalResponse(res, &data)
return data.Projects, err
},
})
diff --git a/plugins/zentao/tasks/shared.go b/plugins/zentao/tasks/shared.go
new file mode 100644
index 00000000..503e1f54
--- /dev/null
+++ b/plugins/zentao/tasks/shared.go
@@ -0,0 +1,34 @@
+/*
+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 (
+ "net/http"
+
+ "github.com/apache/incubator-devlake/plugins/helper"
+)
+
+func GetTotalPagesFromResponse(res *http.Response, args *helper.ApiCollectorArgs) (int, error) {
+ body := &ZentaoPagination{}
+ err := helper.UnmarshalResponse(res, body)
+ if err != nil {
+ return 0, err
+ }
+ return body.Page, nil
+
+}
[incubator-devlake] 07/12: feat(zentao): add execution
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 47f3ecd6f1e500fa84a2aa8b6b818e891a236d07
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Mon Sep 19 10:38:53 2022 +0800
feat(zentao): add execution
---
plugins/zentao/impl/impl.go | 2 +
plugins/zentao/models/archived/execution.go | 151 +++++++++++++++++++++
plugins/zentao/models/execution.go | 151 +++++++++++++++++++++
.../migrationscripts/20220906_add_init_tables.go | 5 +-
plugins/zentao/tasks/execution_collector.go | 79 +++++++++++
plugins/zentao/tasks/execution_extractor.go | 67 +++++++++
6 files changed, 453 insertions(+), 2 deletions(-)
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index f24f6afe..920bced0 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -54,6 +54,8 @@ func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
return []core.SubTaskMeta{
tasks.CollectProjectMeta,
tasks.ExtractProjectsMeta,
+ tasks.CollectExecutionMeta,
+ tasks.ExtractExecutionsMeta,
}
}
diff --git a/plugins/zentao/models/archived/execution.go b/plugins/zentao/models/archived/execution.go
new file mode 100644
index 00000000..787527c1
--- /dev/null
+++ b/plugins/zentao/models/archived/execution.go
@@ -0,0 +1,151 @@
+package archived
+
+import (
+ "github.com/apache/incubator-devlake/models/migrationscripts/archived"
+ "time"
+)
+
+type ZentaoExecution struct {
+ ConnectionId uint64 `gorm:"primaryKey"`
+ Id uint64 `json:"id"`
+ Project uint64 `json:"project"`
+ Model string `json:"model"`
+ Type string `json:"type"`
+ Lifetime string `json:"lifetime"`
+ Budget string `json:"budget"`
+ BudgetUnit string `json:"budgetUnit"`
+ Attribute string `json:"attribute"`
+ Percent int `json:"percent"`
+ Milestone string `json:"milestone"`
+ Output string `json:"output"`
+ Auth string `json:"auth"`
+ Parent int `json:"parent"`
+ Path string `json:"path"`
+ Grade int `json:"grade"`
+ Name string `json:"name"`
+ Code string `json:"code"`
+ Begin string `json:"begin"`
+ End string `json:"end"`
+ RealBegan string `json:"realBegan"`
+ RealEnd string `json:"realEnd"`
+ Days int `json:"days"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Pri string `json:"pri"`
+ Desc string `json:"desc"`
+ Version int `json:"version"`
+ ParentVersion int `json:"parentVersion"`
+ PlanDuration int `json:"planDuration"`
+ RealDuration int `json:"realDuration"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate time.Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate time.Time `json:"lastEditedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate time.Time `json:"closedDate"`
+ CanceledBy `json:"canceledBy"`
+ CanceledDate time.Time `json:"canceledDate"`
+ SuspendedDate string `json:"suspendedDate"`
+ PO `json:"PO"`
+ PM `json:"PM"`
+ QD `json:"QD"`
+ RD `json:"RD"`
+ Team string `json:"team"`
+ Acl string `json:"acl"`
+ //Whitelist []Whitelist `json:"whitelist" gorm:"-:all"`
+ Order int `json:"order"`
+ Vision string `json:"vision"`
+ DisplayCards int `json:"displayCards"`
+ FluidBoard string `json:"fluidBoard"`
+ Deleted bool `json:"deleted"`
+ TotalHours int `json:"totalHours"`
+ TotalEstimate int `json:"totalEstimate"`
+ TotalConsumed int `json:"totalConsumed"`
+ TotalLeft int `json:"totalLeft"`
+ ProjectInfo bool `json:"projectInfo"`
+ Progress int `json:"progress"`
+ TeamMembers []TeamMember `json:"teamMembers" gorm:"-:all"`
+ Products []Product `json:"products" gorm:"-:all"`
+ CaseReview bool `json:"caseReview"`
+ archived.NoPKModel
+}
+
+type OpenedBy struct {
+ OpenedByID int `json:"id"`
+ OpenedByAccount string `json:"account"`
+ OpenedByAvatar string `json:"avatar"`
+ OpenedByRealname string `json:"realname"`
+}
+
+type LastEditedBy struct {
+ LastEditedByID int `json:"id"`
+ LastEditedByAccount string `json:"account"`
+ LastEditedByAvatar string `json:"avatar"`
+ LastEditedByRealname string `json:"realname"`
+}
+
+type ClosedBy struct {
+ ClosedByID int `json:"id"`
+ ClosedByAccount string `json:"account"`
+ ClosedByAvatar string `json:"avatar"`
+ ClosedByRealname string `json:"realname"`
+}
+
+type CanceledBy struct {
+ CanceledByID int `json:"id"`
+ CanceledByAccount string `json:"account"`
+ CanceledByAvatar string `json:"avatar"`
+ CanceledByRealname string `json:"realname"`
+}
+
+type PO struct {
+ PoID int `json:"id"`
+ PoAccount string `json:"account"`
+ PoAvatar string `json:"avatar"`
+ PoRealname string `json:"realname"`
+}
+
+type QD struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type RD struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type Product struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Plans []interface{} `json:"plans"`
+}
+
+type TeamMember struct {
+ ID int `json:"id"`
+ Root int `json:"root"`
+ Type string `json:"type"`
+ Account string `json:"account"`
+ Role string `json:"role"`
+ Position string `json:"position"`
+ Limited string `json:"limited"`
+ Join string `json:"join"`
+ Days int `json:"days"`
+ Hours int `json:"hours"`
+ Estimate string `json:"estimate"`
+ Consumed string `json:"consumed"`
+ Left string `json:"left"`
+ Order int `json:"order"`
+ TotalHours int `json:"totalHours"`
+ UserID int `json:"userID"`
+ Realname string `json:"realname"`
+}
+
+func (ZentaoExecution) TableName() string {
+ return "_tool_zentao_execution"
+}
diff --git a/plugins/zentao/models/execution.go b/plugins/zentao/models/execution.go
new file mode 100644
index 00000000..e51102cf
--- /dev/null
+++ b/plugins/zentao/models/execution.go
@@ -0,0 +1,151 @@
+package models
+
+import (
+ "github.com/apache/incubator-devlake/models/common"
+ "time"
+)
+
+type ZentaoExecution struct {
+ ConnectionId uint64 `gorm:"primaryKey"`
+ Id uint64 `json:"id"`
+ Project uint64 `json:"project"`
+ Model string `json:"model"`
+ Type string `json:"type"`
+ Lifetime string `json:"lifetime"`
+ Budget string `json:"budget"`
+ BudgetUnit string `json:"budgetUnit"`
+ Attribute string `json:"attribute"`
+ Percent int `json:"percent"`
+ Milestone string `json:"milestone"`
+ Output string `json:"output"`
+ Auth string `json:"auth"`
+ Parent int `json:"parent"`
+ Path string `json:"path"`
+ Grade int `json:"grade"`
+ Name string `json:"name"`
+ Code string `json:"code"`
+ Begin string `json:"begin"`
+ End string `json:"end"`
+ RealBegan string `json:"realBegan"`
+ RealEnd string `json:"realEnd"`
+ Days int `json:"days"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Pri string `json:"pri"`
+ Desc string `json:"desc"`
+ Version int `json:"version"`
+ ParentVersion int `json:"parentVersion"`
+ PlanDuration int `json:"planDuration"`
+ RealDuration int `json:"realDuration"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate time.Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate time.Time `json:"lastEditedDate"`
+ ClosedBy `json:"closedBy"`
+ ClosedDate time.Time `json:"closedDate"`
+ CanceledBy `json:"canceledBy"`
+ CanceledDate time.Time `json:"canceledDate"`
+ SuspendedDate string `json:"suspendedDate"`
+ PO `json:"PO"`
+ PM `json:"PM"`
+ QD `json:"QD"`
+ RD `json:"RD"`
+ Team string `json:"team"`
+ Acl string `json:"acl"`
+ //Whitelist []Whitelist `json:"whitelist" gorm:"-:all"`
+ Order int `json:"order"`
+ Vision string `json:"vision"`
+ DisplayCards int `json:"displayCards"`
+ FluidBoard string `json:"fluidBoard"`
+ Deleted bool `json:"deleted"`
+ TotalHours int `json:"totalHours"`
+ TotalEstimate int `json:"totalEstimate"`
+ TotalConsumed int `json:"totalConsumed"`
+ TotalLeft int `json:"totalLeft"`
+ ProjectInfo bool `json:"projectInfo"`
+ Progress int `json:"progress"`
+ TeamMembers []TeamMember `json:"teamMembers" gorm:"-:all"`
+ Products []Product `json:"products" gorm:"-:all"`
+ CaseReview bool `json:"caseReview"`
+ common.NoPKModel
+}
+
+func (ZentaoExecution) TableName() string {
+ return "_tool_zentao_execution"
+}
+
+type OpenedBy struct {
+ OpenedByID int `json:"id"`
+ OpenedByAccount string `json:"account"`
+ OpenedByAvatar string `json:"avatar"`
+ OpenedByRealname string `json:"realname"`
+}
+
+type LastEditedBy struct {
+ LastEditedByID int `json:"id"`
+ LastEditedByAccount string `json:"account"`
+ LastEditedByAvatar string `json:"avatar"`
+ LastEditedByRealname string `json:"realname"`
+}
+
+type ClosedBy struct {
+ ClosedByID int `json:"id"`
+ ClosedByAccount string `json:"account"`
+ ClosedByAvatar string `json:"avatar"`
+ ClosedByRealname string `json:"realname"`
+}
+
+type CanceledBy struct {
+ CanceledByID int `json:"id"`
+ CanceledByAccount string `json:"account"`
+ CanceledByAvatar string `json:"avatar"`
+ CanceledByRealname string `json:"realname"`
+}
+
+type PO struct {
+ PoID int `json:"id"`
+ PoAccount string `json:"account"`
+ PoAvatar string `json:"avatar"`
+ PoRealname string `json:"realname"`
+}
+
+type QD struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type RD struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ Realname string `json:"realname"`
+}
+
+type Product struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+ Plans []interface{} `json:"plans"`
+}
+
+type TeamMember struct {
+ ID int `json:"id"`
+ Root int `json:"root"`
+ Type string `json:"type"`
+ Account string `json:"account"`
+ Role string `json:"role"`
+ Position string `json:"position"`
+ Limited string `json:"limited"`
+ Join string `json:"join"`
+ Days int `json:"days"`
+ Hours int `json:"hours"`
+ Estimate string `json:"estimate"`
+ Consumed string `json:"consumed"`
+ Left string `json:"left"`
+ Order int `json:"order"`
+ TotalHours int `json:"totalHours"`
+ UserID int `json:"userID"`
+ Realname string `json:"realname"`
+}
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index 1a743c46..6635dda3 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -27,8 +27,9 @@ type addInitTables struct{}
func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
return db.Migrator().AutoMigrate(
- archived.ZentaoConnection{},
- archived.ZentaoProject{},
+ //archived.ZentaoConnection{},
+ //archived.ZentaoProject{},
+ archived.ZentaoExecution{},
)
}
diff --git a/plugins/zentao/tasks/execution_collector.go b/plugins/zentao/tasks/execution_collector.go
new file mode 100644
index 00000000..b012084f
--- /dev/null
+++ b/plugins/zentao/tasks/execution_collector.go
@@ -0,0 +1,79 @@
+/*
+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 (
+ "encoding/json"
+ "fmt"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "io"
+ "net/http"
+ "net/url"
+)
+
+const RAW_EXECUTION_TABLE = "zentao_execution"
+
+var _ core.SubTaskEntryPoint = CollectExecution
+
+func CollectExecution(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ collector, err := helper.NewApiCollector(helper.ApiCollectorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_EXECUTION_TABLE,
+ },
+ ApiClient: data.ApiClient,
+ Incremental: false,
+ PageSize: 100,
+ // TODO write which api would you want request
+ UrlTemplate: "executions/{{ .Params.ExecutionId }}",
+ Query: func(reqData *helper.RequestData) (url.Values, error) {
+ query := url.Values{}
+ query.Set("page", fmt.Sprintf("%v", reqData.Pager.Page))
+ query.Set("limit", fmt.Sprintf("%v", reqData.Pager.Size))
+ return query, nil
+ },
+ GetTotalPages: GetTotalPagesFromResponse,
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
+ body, err := io.ReadAll(res.Body)
+ res.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ return []json.RawMessage{body}, nil
+ },
+ })
+ if err != nil {
+ return err
+ }
+
+ return collector.Execute()
+}
+
+var CollectExecutionMeta = core.SubTaskMeta{
+ Name: "CollectExecution",
+ EntryPoint: CollectExecution,
+ EnabledByDefault: true,
+ Description: "Collect Execution data from Zentao api",
+}
diff --git a/plugins/zentao/tasks/execution_extractor.go b/plugins/zentao/tasks/execution_extractor.go
new file mode 100644
index 00000000..f8b42226
--- /dev/null
+++ b/plugins/zentao/tasks/execution_extractor.go
@@ -0,0 +1,67 @@
+/*
+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 (
+ "encoding/json"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+)
+
+var _ core.SubTaskEntryPoint = ExtractExecutions
+
+var ExtractExecutionsMeta = core.SubTaskMeta{
+ Name: "extractExecutions",
+ EntryPoint: ExtractExecutions,
+ EnabledByDefault: true,
+ Description: "extract Zentao executions",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ExtractExecutions(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_EXECUTION_TABLE,
+ },
+ Extract: func(row *helper.RawData) ([]interface{}, error) {
+ execution := &models.ZentaoExecution{}
+ err := json.Unmarshal(row.Data, execution)
+ if err != nil {
+ return nil, err
+ }
+ execution.ConnectionId = data.Options.ConnectionId
+ results := make([]interface{}, 0)
+ results = append(results, execution)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return extractor.Execute()
+}
[incubator-devlake] 08/12: feat(zentao): fix execution time
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 9919d22f29f03cbd6dbc4420039eb07899e73335
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Mon Sep 19 11:05:59 2022 +0800
feat(zentao): fix execution time
---
plugins/helper/iso8601time.go | 31 ++++++++++
plugins/zentao/impl/impl.go | 1 +
plugins/zentao/models/archived/execution.go | 78 ++++++++++++-------------
plugins/zentao/models/archived/project.go | 4 +-
plugins/zentao/models/execution.go | 78 ++++++++++++-------------
plugins/zentao/models/project.go | 4 +-
plugins/zentao/tasks/execution_convertor.go | 91 +++++++++++++++++++++++++++++
7 files changed, 205 insertions(+), 82 deletions(-)
diff --git a/plugins/helper/iso8601time.go b/plugins/helper/iso8601time.go
index 8d409262..3029adb1 100644
--- a/plugins/helper/iso8601time.go
+++ b/plugins/helper/iso8601time.go
@@ -18,6 +18,7 @@ limitations under the License.
package helper
import (
+ "database/sql/driver"
"fmt"
"regexp"
"strings"
@@ -63,6 +64,10 @@ func init() {
Matcher: regexp.MustCompile(`[+-][\d]{2}:[\d]{2}$`),
Format: "2006-01-02T15:04:05-07:00",
},
+ {
+ Matcher: regexp.MustCompile(`[+-][\d]{2}-[\d]{2}$`),
+ Format: "2006-01-02",
+ },
}
}
@@ -131,3 +136,29 @@ func Iso8601TimeToTime(iso8601Time *Iso8601Time) *time.Time {
t := iso8601Time.ToTime()
return &t
}
+
+// Value FIXME ...
+func (jt *Iso8601Time) Value() (driver.Value, error) {
+ if jt == nil {
+ return nil, nil
+ }
+ var zeroTime time.Time
+ t := jt.time
+ if t.UnixNano() == zeroTime.UnixNano() {
+ return nil, nil
+ }
+ return t, nil
+}
+
+// Scan FIXME ...
+func (jt *Iso8601Time) Scan(v interface{}) error {
+ value, ok := v.(time.Time)
+ if ok {
+ *jt = Iso8601Time{
+ time: value,
+ format: time.RFC3339,
+ }
+ return nil
+ }
+ return fmt.Errorf("can not convert %v to timestamp", v)
+}
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index 920bced0..b4004753 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -56,6 +56,7 @@ func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
tasks.ExtractProjectsMeta,
tasks.CollectExecutionMeta,
tasks.ExtractExecutionsMeta,
+ tasks.ConvertExecutionsMeta,
}
}
diff --git a/plugins/zentao/models/archived/execution.go b/plugins/zentao/models/archived/execution.go
index 787527c1..7fe6cd16 100644
--- a/plugins/zentao/models/archived/execution.go
+++ b/plugins/zentao/models/archived/execution.go
@@ -2,51 +2,51 @@ package archived
import (
"github.com/apache/incubator-devlake/models/migrationscripts/archived"
- "time"
+ "github.com/apache/incubator-devlake/plugins/helper"
)
type ZentaoExecution struct {
- ConnectionId uint64 `gorm:"primaryKey"`
- Id uint64 `json:"id"`
- Project uint64 `json:"project"`
- Model string `json:"model"`
- Type string `json:"type"`
- Lifetime string `json:"lifetime"`
- Budget string `json:"budget"`
- BudgetUnit string `json:"budgetUnit"`
- Attribute string `json:"attribute"`
- Percent int `json:"percent"`
- Milestone string `json:"milestone"`
- Output string `json:"output"`
- Auth string `json:"auth"`
- Parent int `json:"parent"`
- Path string `json:"path"`
- Grade int `json:"grade"`
- Name string `json:"name"`
- Code string `json:"code"`
- Begin string `json:"begin"`
- End string `json:"end"`
- RealBegan string `json:"realBegan"`
- RealEnd string `json:"realEnd"`
- Days int `json:"days"`
- Status string `json:"status"`
- SubStatus string `json:"subStatus"`
- Pri string `json:"pri"`
- Desc string `json:"desc"`
- Version int `json:"version"`
- ParentVersion int `json:"parentVersion"`
- PlanDuration int `json:"planDuration"`
- RealDuration int `json:"realDuration"`
+ ConnectionId uint64 `gorm:"primaryKey"`
+ Id uint64 `json:"id" gorm:"primaryKey"`
+ Project uint64 `json:"project"`
+ Model string `json:"model"`
+ Type string `json:"type"`
+ Lifetime string `json:"lifetime"`
+ Budget string `json:"budget"`
+ BudgetUnit string `json:"budgetUnit"`
+ Attribute string `json:"attribute"`
+ Percent int `json:"percent"`
+ Milestone string `json:"milestone"`
+ Output string `json:"output"`
+ Auth string `json:"auth"`
+ Parent int `json:"parent"`
+ Path string `json:"path"`
+ Grade int `json:"grade"`
+ Name string `json:"name"`
+ Code string `json:"code"`
+ Begin *helper.Iso8601Time `json:"begin"`
+ End *helper.Iso8601Time `json:"end"`
+ RealBegan *helper.Iso8601Time `json:"realBegan"`
+ RealEnd *helper.Iso8601Time `json:"realEnd"`
+ Days int `json:"days"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Pri string `json:"pri"`
+ Desc string `json:"desc"`
+ Version int `json:"version"`
+ ParentVersion int `json:"parentVersion"`
+ PlanDuration int `json:"planDuration"`
+ RealDuration int `json:"realDuration"`
OpenedBy `json:"openedBy"`
- OpenedDate time.Time `json:"openedDate"`
- OpenedVersion string `json:"openedVersion"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
LastEditedBy `json:"lastEditedBy"`
- LastEditedDate time.Time `json:"lastEditedDate"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
ClosedBy `json:"closedBy"`
- ClosedDate time.Time `json:"closedDate"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
CanceledBy `json:"canceledBy"`
- CanceledDate time.Time `json:"canceledDate"`
- SuspendedDate string `json:"suspendedDate"`
+ CanceledDate *helper.Iso8601Time `json:"canceledDate"`
+ SuspendedDate *helper.Iso8601Time `json:"suspendedDate"`
PO `json:"PO"`
PM `json:"PM"`
QD `json:"QD"`
@@ -147,5 +147,5 @@ type TeamMember struct {
}
func (ZentaoExecution) TableName() string {
- return "_tool_zentao_execution"
+ return "_tool_zentao_executions"
}
diff --git a/plugins/zentao/models/archived/project.go b/plugins/zentao/models/archived/project.go
index 63c498dd..94fcdfcb 100644
--- a/plugins/zentao/models/archived/project.go
+++ b/plugins/zentao/models/archived/project.go
@@ -25,7 +25,7 @@ import (
type ZentaoProject struct {
archived.NoPKModel
ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
- ID int `json:"id"`
+ ID int `json:"id" gorm:"primaryKey;type:BIGINT NOT NULL"`
Project int `json:"project"`
Model string `json:"model"`
Type string `json:"type"`
@@ -109,5 +109,5 @@ type Hours struct {
}
func (ZentaoProject) TableName() string {
- return "_tool_zentao_project"
+ return "_tool_zentao_projects"
}
diff --git a/plugins/zentao/models/execution.go b/plugins/zentao/models/execution.go
index e51102cf..054f21d7 100644
--- a/plugins/zentao/models/execution.go
+++ b/plugins/zentao/models/execution.go
@@ -2,51 +2,51 @@ package models
import (
"github.com/apache/incubator-devlake/models/common"
- "time"
+ "github.com/apache/incubator-devlake/plugins/helper"
)
type ZentaoExecution struct {
- ConnectionId uint64 `gorm:"primaryKey"`
- Id uint64 `json:"id"`
- Project uint64 `json:"project"`
- Model string `json:"model"`
- Type string `json:"type"`
- Lifetime string `json:"lifetime"`
- Budget string `json:"budget"`
- BudgetUnit string `json:"budgetUnit"`
- Attribute string `json:"attribute"`
- Percent int `json:"percent"`
- Milestone string `json:"milestone"`
- Output string `json:"output"`
- Auth string `json:"auth"`
- Parent int `json:"parent"`
- Path string `json:"path"`
- Grade int `json:"grade"`
- Name string `json:"name"`
- Code string `json:"code"`
- Begin string `json:"begin"`
- End string `json:"end"`
- RealBegan string `json:"realBegan"`
- RealEnd string `json:"realEnd"`
- Days int `json:"days"`
- Status string `json:"status"`
- SubStatus string `json:"subStatus"`
- Pri string `json:"pri"`
- Desc string `json:"desc"`
- Version int `json:"version"`
- ParentVersion int `json:"parentVersion"`
- PlanDuration int `json:"planDuration"`
- RealDuration int `json:"realDuration"`
+ ConnectionId uint64 `gorm:"primaryKey"`
+ Id uint64 `json:"id" gorm:"primaryKey"`
+ Project uint64 `json:"project"`
+ Model string `json:"model"`
+ Type string `json:"type"`
+ Lifetime string `json:"lifetime"`
+ Budget string `json:"budget"`
+ BudgetUnit string `json:"budgetUnit"`
+ Attribute string `json:"attribute"`
+ Percent int `json:"percent"`
+ Milestone string `json:"milestone"`
+ Output string `json:"output"`
+ Auth string `json:"auth"`
+ Parent int `json:"parent"`
+ Path string `json:"path"`
+ Grade int `json:"grade"`
+ Name string `json:"name"`
+ Code string `json:"code"`
+ Begin *helper.Iso8601Time `json:"begin"`
+ End *helper.Iso8601Time `json:"end"`
+ RealBegan *helper.Iso8601Time `json:"realBegan"`
+ RealEnd *helper.Iso8601Time `json:"realEnd"`
+ Days int `json:"days"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Pri string `json:"pri"`
+ Desc string `json:"desc"`
+ Version int `json:"version"`
+ ParentVersion int `json:"parentVersion"`
+ PlanDuration int `json:"planDuration"`
+ RealDuration int `json:"realDuration"`
OpenedBy `json:"openedBy"`
- OpenedDate time.Time `json:"openedDate"`
- OpenedVersion string `json:"openedVersion"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
LastEditedBy `json:"lastEditedBy"`
- LastEditedDate time.Time `json:"lastEditedDate"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
ClosedBy `json:"closedBy"`
- ClosedDate time.Time `json:"closedDate"`
+ ClosedDate *helper.Iso8601Time `json:"closedDate"`
CanceledBy `json:"canceledBy"`
- CanceledDate time.Time `json:"canceledDate"`
- SuspendedDate string `json:"suspendedDate"`
+ CanceledDate *helper.Iso8601Time `json:"canceledDate"`
+ SuspendedDate *helper.Iso8601Time `json:"suspendedDate"`
PO `json:"PO"`
PM `json:"PM"`
QD `json:"QD"`
@@ -72,7 +72,7 @@ type ZentaoExecution struct {
}
func (ZentaoExecution) TableName() string {
- return "_tool_zentao_execution"
+ return "_tool_zentao_executions"
}
type OpenedBy struct {
diff --git a/plugins/zentao/models/project.go b/plugins/zentao/models/project.go
index 5a51d738..db9450bf 100644
--- a/plugins/zentao/models/project.go
+++ b/plugins/zentao/models/project.go
@@ -25,7 +25,7 @@ import (
type ZentaoProject struct {
common.NoPKModel
ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
- ID int `json:"id"`
+ ID int `json:"id" gorm:"primaryKey;type:BIGINT NOT NULL"`
Project int `json:"project"`
Model string `json:"model"`
Type string `json:"type"`
@@ -109,5 +109,5 @@ type Hours struct {
}
func (ZentaoProject) TableName() string {
- return "_tool_zentao_project"
+ return "_tool_zentao_projects"
}
diff --git a/plugins/zentao/tasks/execution_convertor.go b/plugins/zentao/tasks/execution_convertor.go
new file mode 100644
index 00000000..727ba92d
--- /dev/null
+++ b/plugins/zentao/tasks/execution_convertor.go
@@ -0,0 +1,91 @@
+/*
+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 (
+ "github.com/apache/incubator-devlake/models/domainlayer"
+ "github.com/apache/incubator-devlake/models/domainlayer/didgen"
+ "github.com/apache/incubator-devlake/models/domainlayer/ticket"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/core/dal"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "reflect"
+)
+
+var _ core.SubTaskEntryPoint = ConvertExecutions
+
+var ConvertExecutionsMeta = core.SubTaskMeta{
+ Name: "convertExecutions",
+ EntryPoint: ConvertExecutions,
+ EnabledByDefault: true,
+ Description: "convert Zentao executions",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ConvertExecutions(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ db := taskCtx.GetDal()
+ boardIdGen := didgen.NewDomainIdGenerator(&models.ZentaoExecution{})
+ cursor, err := db.Cursor(
+ dal.From(&models.ZentaoExecution{}),
+ dal.Where(`_tool_zentao_executions.id = ? and
+ _tool_zentao_executions.connection_id = ?`, data.Options.ExecutionId, data.Options.ConnectionId),
+ )
+ if err != nil {
+ return err
+ }
+ defer cursor.Close()
+ convertor, err := helper.NewDataConverter(helper.DataConverterArgs{
+ InputRowType: reflect.TypeOf(models.ZentaoExecution{}),
+ Input: cursor,
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
+ },
+ Table: RAW_EXECUTION_TABLE,
+ },
+ Convert: func(inputRow interface{}) ([]interface{}, error) {
+ toolExecution := inputRow.(*models.ZentaoExecution)
+
+ domainBoard := &ticket.Board{
+ DomainEntity: domainlayer.DomainEntity{
+ Id: boardIdGen.Generate(toolExecution.ConnectionId, toolExecution.Id),
+ },
+ Name: toolExecution.Name,
+ Description: toolExecution.Desc,
+ Url: toolExecution.Path,
+ CreatedDate: toolExecution.OpenedDate.ToNullableTime(),
+ Type: toolExecution.Type,
+ }
+
+ results := make([]interface{}, 0)
+ results = append(results, domainBoard)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return convertor.Execute()
+}
[incubator-devlake] 10/12: fix:apiurl&model error
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 8f3ff2c706b7cdb4ca6691b159bde4faeee3545b
Author: yuqiangabab <11...@qq.com>
AuthorDate: Sun Oct 2 11:20:52 2022 +0800
fix:apiurl&model error
---
plugins/zentao/models/archived/stories.go | 116 +++++++-----------------------
plugins/zentao/models/stories.go | 116 +++++++-----------------------
plugins/zentao/tasks/stories_collector.go | 12 +++-
plugins/zentao/tasks/stories_convertor.go | 18 ++---
plugins/zentao/tasks/stories_extractor.go | 5 +-
plugins/zentao/tasks/task_data.go | 1 -
plugins/zentao/zentao.go | 2 -
7 files changed, 75 insertions(+), 195 deletions(-)
diff --git a/plugins/zentao/models/archived/stories.go b/plugins/zentao/models/archived/stories.go
index cd608682..d197e1fd 100644
--- a/plugins/zentao/models/archived/stories.go
+++ b/plugins/zentao/models/archived/stories.go
@@ -25,11 +25,16 @@ import (
type ZentaoStories struct {
archived.NoPKModel
ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
- ID int `json:"id"gorm:"primaryKey;type:BIGINT NOT NULL"`
- Vision string `json:"vision"`
- Parent int `json:"parent"`
+ ExecutionId uint64 `json:"execution_id"`
+ Project int `json:"project"`
Product int `json:"product"`
Branch int `json:"branch"`
+ Story int `json:"story"`
+ Version int `json:"version"`
+ Order int `json:"order"`
+ ID int `json:"id" gorm:"primaryKey;type:BIGINT NOT NULL" `
+ Vision string `json:"vision"`
+ Parent int `json:"parent"`
Module int `json:"module"`
Plan string `json:"plan"`
Source string `json:"source"`
@@ -47,20 +52,20 @@ type ZentaoStories struct {
Color string `json:"color"`
Stage string `json:"stage"`
StagedBy string `json:"stagedBy"`
- //Mailto []interface{} `json:"mailto" gorm:"-:all"`
- Lib int `json:"lib"`
- FromStory int `json:"fromStory"`
- FromVersion int `json:"fromVersion"`
- OpenedBy `json:"openedBy"`
- OpenedDate *helper.Iso8601Time `json:"openedDate"`
- AssignedTo `json:"assignedTo"`
- AssignedDate *helper.Iso8601Time `json:"assignedDate"`
- ApprovedDate string `json:"approvedDate"`
- LastEditedBy `json:"lastEditedBy"`
- LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
- ChangedBy string `json:"changedBy"`
- ChangedDate string `json:"changedDate"`
- ReviewedBy interface{} `json:"reviewedBy" gorm:"-:all"`
+ //Mailto []interface{} `json:"mailto"`
+ Lib int `json:"lib"`
+ FromStory int `json:"fromStory"`
+ FromVersion int `json:"fromVersion"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ ApprovedDate string `json:"approvedDate"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ ChangedBy string `json:"changedBy"`
+ ChangedDate string `json:"changedDate"`
+ //ReviewedBy interface{} `json:"reviewedBy"`
ReviewedDate *helper.Iso8601Time `json:"reviewedDate"`
ClosedBy `json:"closedBy"`
ClosedDate *helper.Iso8601Time `json:"closedDate"`
@@ -71,81 +76,17 @@ type ZentaoStories struct {
LinkStories string `json:"linkStories"`
LinkRequirements string `json:"linkRequirements"`
DuplicateStory int `json:"duplicateStory"`
- Version int `json:"version"`
StoryChanged string `json:"storyChanged"`
FeedbackBy string `json:"feedbackBy"`
NotifyEmail string `json:"notifyEmail"`
URChanged string `json:"URChanged"`
Deleted bool `json:"deleted"`
- Spec string `json:"spec"`
- Verify string `json:"verify"`
- Executions Executions `json:"executions" gorm:"-:all"`
- Tasks []Tasks `json:"tasks" gorm:"-:all"`
- //Stages []interface{} `json:"stages" gorm:"-:all"`
- PlanTitle []string `json:"planTitle" gorm:"-:all"`
- //Children []interface{} `json:"children" gorm:"-:all"`
- //Files []interface{} `json:"files" gorm:"-:all"`
- ProductName string `json:"productName"`
- ProductStatus string `json:"productStatus"`
- ModuleTitle string `json:"moduleTitle"`
- Bugs []Bugs `json:"bugs" gorm:"-:all"`
- Cases []Cases `json:"cases" gorm:"-:all"`
- //Requirements []interface{} `json:"requirements" gorm:"-:all"`
- Actions []Actions `json:"actions" gorm:"-:all"`
- PreAndNext `json:"preAndNext"`
-}
-type Executions struct {
- Num1 struct {
- Project int `json:"project"`
- Name string `json:"name"`
- Status string `json:"status"`
- Type string `json:"type"`
- } `json:"1"`
-}
-type Tasks struct {
- ID int `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
- Status string `json:"status"`
- AssignedTo struct {
- ID int `json:"id"`
- Account string `json:"account"`
- Avatar string `json:"avatar"`
- Realname string `json:"realname"`
- } `json:"assignedTo"`
-}
-type Bugs struct {
- ID int `json:"id"`
- Title string `json:"title"`
- Status string `json:"status"`
- Pri int `json:"pri"`
- Severity int `json:"severity"`
-}
-type Cases struct {
- ID int `json:"id"`
- Title string `json:"title"`
- Pri int `json:"pri"`
- Status string `json:"status"`
+ PriOrder string `json:"priOrder"`
+ ProductType string `json:"productType"`
+ PlanTitle string `json:"planTitle"`
+ ProductStatus string `json:"productStatus"`
}
-type Actions struct {
- ID int `json:"id"`
- ObjectType string `json:"objectType"`
- ObjectID int `json:"objectID"`
- Product string `json:"product"`
- Project int `json:"project"`
- Execution int `json:"execution"`
- Actor string `json:"actor"`
- Action string `json:"action"`
- Date string `json:"date"`
- Comment string `json:"comment"`
- Extra string `json:"extra"`
- Read string `json:"read"`
- Vision string `json:"vision"`
- Efforted int `json:"efforted"`
- //History []interface{} `json:"history"`
- Desc string `json:"desc"`
-}
type AssignedTo struct {
ID int `json:"id"`
Account string `json:"account"`
@@ -153,11 +94,6 @@ type AssignedTo struct {
Realname string `json:"realname"`
}
-type PreAndNext struct {
- Pre string `json:"pre"`
- Next string `json:"next"`
-}
-
func (ZentaoStories) TableName() string {
return "_tool_zentao_stories"
}
diff --git a/plugins/zentao/models/stories.go b/plugins/zentao/models/stories.go
index be198bbf..1d65c111 100644
--- a/plugins/zentao/models/stories.go
+++ b/plugins/zentao/models/stories.go
@@ -25,11 +25,16 @@ import (
type ZentaoStories struct {
common.NoPKModel
ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
- ID int `json:"id"gorm:"primaryKey;type:BIGINT NOT NULL"`
- Vision string `json:"vision"`
- Parent int `json:"parent"`
+ ExecutionId uint64 `json:"execution_id"`
+ Project int `json:"project"`
Product int `json:"product"`
Branch int `json:"branch"`
+ Story int `json:"story"`
+ Version int `json:"version"`
+ Order int `json:"order"`
+ ID int `json:"id" gorm:"primaryKey;type:BIGINT NOT NULL" `
+ Vision string `json:"vision"`
+ Parent int `json:"parent"`
Module int `json:"module"`
Plan string `json:"plan"`
Source string `json:"source"`
@@ -47,20 +52,20 @@ type ZentaoStories struct {
Color string `json:"color"`
Stage string `json:"stage"`
StagedBy string `json:"stagedBy"`
- //Mailto []interface{} `json:"mailto" gorm:"-:all"`
- Lib int `json:"lib"`
- FromStory int `json:"fromStory"`
- FromVersion int `json:"fromVersion"`
- OpenedBy `json:"openedBy"`
- OpenedDate *helper.Iso8601Time `json:"openedDate"`
- AssignedTo `json:"assignedTo"`
- AssignedDate *helper.Iso8601Time `json:"assignedDate"`
- ApprovedDate string `json:"approvedDate"`
- LastEditedBy `json:"lastEditedBy"`
- LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
- ChangedBy string `json:"changedBy"`
- ChangedDate string `json:"changedDate"`
- ReviewedBy interface{} `json:"reviewedBy" gorm:"-:all"`
+ //Mailto []interface{} `json:"mailto"`
+ Lib int `json:"lib"`
+ FromStory int `json:"fromStory"`
+ FromVersion int `json:"fromVersion"`
+ OpenedBy `json:"openedBy"`
+ OpenedDate *helper.Iso8601Time `json:"openedDate"`
+ AssignedTo `json:"assignedTo"`
+ AssignedDate *helper.Iso8601Time `json:"assignedDate"`
+ ApprovedDate string `json:"approvedDate"`
+ LastEditedBy `json:"lastEditedBy"`
+ LastEditedDate *helper.Iso8601Time `json:"lastEditedDate"`
+ ChangedBy string `json:"changedBy"`
+ ChangedDate string `json:"changedDate"`
+ //ReviewedBy interface{} `json:"reviewedBy"`
ReviewedDate *helper.Iso8601Time `json:"reviewedDate"`
ClosedBy `json:"closedBy"`
ClosedDate *helper.Iso8601Time `json:"closedDate"`
@@ -71,81 +76,17 @@ type ZentaoStories struct {
LinkStories string `json:"linkStories"`
LinkRequirements string `json:"linkRequirements"`
DuplicateStory int `json:"duplicateStory"`
- Version int `json:"version"`
StoryChanged string `json:"storyChanged"`
FeedbackBy string `json:"feedbackBy"`
NotifyEmail string `json:"notifyEmail"`
URChanged string `json:"URChanged"`
Deleted bool `json:"deleted"`
- Spec string `json:"spec"`
- Verify string `json:"verify"`
- Executions Executions `json:"executions" gorm:"-:all"`
- Tasks []Tasks `json:"tasks" gorm:"-:all"`
- //Stages []interface{} `json:"stages" gorm:"-:all"`
- PlanTitle []string `json:"planTitle" gorm:"-:all"`
- //Children []interface{} `json:"children" gorm:"-:all"`
- //Files []interface{} `json:"files" gorm:"-:all"`
- ProductName string `json:"productName"`
- ProductStatus string `json:"productStatus"`
- ModuleTitle string `json:"moduleTitle"`
- Bugs []Bugs `json:"bugs" gorm:"-:all"`
- Cases []Cases `json:"cases" gorm:"-:all"`
- //Requirements []interface{} `json:"requirements" gorm:"-:all"`
- Actions []Actions `json:"actions" gorm:"-:all"`
- PreAndNext `json:"preAndNext"`
-}
-type Executions struct {
- Num1 struct {
- Project int `json:"project"`
- Name string `json:"name"`
- Status string `json:"status"`
- Type string `json:"type"`
- } `json:"1"`
-}
-type Tasks struct {
- ID int `json:"id"`
- Name string `json:"name"`
- Type string `json:"type"`
- Status string `json:"status"`
- AssignedTo struct {
- ID int `json:"id"`
- Account string `json:"account"`
- Avatar string `json:"avatar"`
- Realname string `json:"realname"`
- } `json:"assignedTo"`
-}
-type Bugs struct {
- ID int `json:"id"`
- Title string `json:"title"`
- Status string `json:"status"`
- Pri int `json:"pri"`
- Severity int `json:"severity"`
-}
-type Cases struct {
- ID int `json:"id"`
- Title string `json:"title"`
- Pri int `json:"pri"`
- Status string `json:"status"`
+ PriOrder string `json:"priOrder"`
+ ProductType string `json:"productType"`
+ PlanTitle string `json:"planTitle"`
+ ProductStatus string `json:"productStatus"`
}
-type Actions struct {
- ID int `json:"id"`
- ObjectType string `json:"objectType"`
- ObjectID int `json:"objectID"`
- Product string `json:"product"`
- Project int `json:"project"`
- Execution int `json:"execution"`
- Actor string `json:"actor"`
- Action string `json:"action"`
- Date string `json:"date"`
- Comment string `json:"comment"`
- Extra string `json:"extra"`
- Read string `json:"read"`
- Vision string `json:"vision"`
- Efforted int `json:"efforted"`
- //History []interface{} `json:"history"`
- Desc string `json:"desc"`
-}
type AssignedTo struct {
ID int `json:"id"`
Account string `json:"account"`
@@ -153,11 +94,6 @@ type AssignedTo struct {
Realname string `json:"realname"`
}
-type PreAndNext struct {
- Pre string `json:"pre"`
- Next string `json:"next"`
-}
-
func (ZentaoStories) TableName() string {
return "_tool_zentao_stories"
}
diff --git a/plugins/zentao/tasks/stories_collector.go b/plugins/zentao/tasks/stories_collector.go
index 6ba58924..26c004c8 100644
--- a/plugins/zentao/tasks/stories_collector.go
+++ b/plugins/zentao/tasks/stories_collector.go
@@ -37,7 +37,9 @@ func CollectStories(taskCtx core.SubTaskContext) error {
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: ZentaoApiParams{
- StoriesId: data.Options.StoriesId,
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
},
Table: RAW_STORIES_TABLE,
},
@@ -45,7 +47,7 @@ func CollectStories(taskCtx core.SubTaskContext) error {
Incremental: false,
PageSize: 100,
// TODO write which api would you want request
- UrlTemplate: "/stories/{{ .Params.StoriesId }}",
+ UrlTemplate: "/executions/{{ .Params.ExecutionId }}/stories",
Query: func(reqData *helper.RequestData) (url.Values, error) {
query := url.Values{}
query.Set("page", fmt.Sprintf("%v", reqData.Pager.Page))
@@ -54,12 +56,16 @@ func CollectStories(taskCtx core.SubTaskContext) error {
},
GetTotalPages: GetTotalPagesFromResponse,
ResponseParser: func(res *http.Response) ([]json.RawMessage, error) {
+ var data struct {
+ Stories []json.RawMessage `json:"stories"`
+ }
body, err := io.ReadAll(res.Body)
+ json.Unmarshal(body, &data)
res.Body.Close()
if err != nil {
return nil, err
}
- return []json.RawMessage{body}, nil
+ return data.Stories, nil
},
})
if err != nil {
diff --git a/plugins/zentao/tasks/stories_convertor.go b/plugins/zentao/tasks/stories_convertor.go
index a41a1868..b9d80724 100644
--- a/plugins/zentao/tasks/stories_convertor.go
+++ b/plugins/zentao/tasks/stories_convertor.go
@@ -44,8 +44,8 @@ func ConvertStories(taskCtx core.SubTaskContext) error {
boardIdGen := didgen.NewDomainIdGenerator(&models.ZentaoStories{})
cursor, err := db.Cursor(
dal.From(&models.ZentaoStories{}),
- dal.Where(`_tool_zentao_stories.id = ? and
- _tool_zentao_stories.connection_id = ?`, data.Options.StoriesId, data.Options.ConnectionId),
+ dal.Where(`_tool_zentao_stories.execution_id = ? and
+ _tool_zentao_stories.connection_id = ?`, data.Options.ExecutionId, data.Options.ConnectionId),
)
if err != nil {
return err
@@ -57,7 +57,9 @@ func ConvertStories(taskCtx core.SubTaskContext) error {
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: ZentaoApiParams{
- StoriesId: data.Options.StoriesId,
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
},
Table: RAW_STORIES_TABLE,
},
@@ -68,11 +70,11 @@ func ConvertStories(taskCtx core.SubTaskContext) error {
DomainEntity: domainlayer.DomainEntity{
Id: boardIdGen.Generate(toolStories.ConnectionId, toolStories.ID),
},
- Url: "",
- IconURL: "",
- IssueKey: "",
- Title: toolStories.Title,
- Description: toolStories.Spec,
+ Url: "",
+ IconURL: "",
+ IssueKey: "",
+ Title: toolStories.Title,
+ //Description: toolStories.Spec,
EpicKey: "",
Type: toolStories.Type,
Status: toolStories.Status,
diff --git a/plugins/zentao/tasks/stories_extractor.go b/plugins/zentao/tasks/stories_extractor.go
index aaadfb84..a4d37db0 100644
--- a/plugins/zentao/tasks/stories_extractor.go
+++ b/plugins/zentao/tasks/stories_extractor.go
@@ -40,7 +40,9 @@ func ExtractStories(taskCtx core.SubTaskContext) error {
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: ZentaoApiParams{
- StoriesId: data.Options.StoriesId,
+ ProductId: data.Options.ProductId,
+ ExecutionId: data.Options.ExecutionId,
+ ProjectId: data.Options.ProjectId,
},
Table: RAW_STORIES_TABLE,
},
@@ -51,6 +53,7 @@ func ExtractStories(taskCtx core.SubTaskContext) error {
return nil, err
}
stories.ConnectionId = data.Options.ConnectionId
+ stories.ExecutionId = data.Options.ExecutionId
results := make([]interface{}, 0)
results = append(results, stories)
return results, nil
diff --git a/plugins/zentao/tasks/task_data.go b/plugins/zentao/tasks/task_data.go
index ae51908f..c522360e 100644
--- a/plugins/zentao/tasks/task_data.go
+++ b/plugins/zentao/tasks/task_data.go
@@ -27,7 +27,6 @@ type ZentaoApiParams struct {
ProductId uint64
ExecutionId uint64
ProjectId uint64
- StoriesId uint64
}
type ZentaoOptions struct {
diff --git a/plugins/zentao/zentao.go b/plugins/zentao/zentao.go
index 3768b5d9..32845c90 100644
--- a/plugins/zentao/zentao.go
+++ b/plugins/zentao/zentao.go
@@ -34,7 +34,6 @@ func main() {
executionId := cmd.Flags().IntP("executionId", "e", 8, "execution id")
productId := cmd.Flags().IntP("productId", "o", 8, "product id")
projectId := cmd.Flags().IntP("projectId", "p", 8, "project id")
- storiesId := cmd.Flags().IntP("storiesId", "s", 1, "stories id")
cmd.Run = func(cmd *cobra.Command, args []string) {
runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
@@ -42,7 +41,6 @@ func main() {
"executionId": *executionId,
"productId": *productId,
"projectId": *projectId,
- "storiesId": *storiesId,
})
}
runner.RunCmd(cmd)
[incubator-devlake] 05/12: feat:add zentao project extractor
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 34298a21aad879dac19bc884f53f6742ccdfd6ee
Author: yuqiangabab <11...@qq.com>
AuthorDate: Sun Sep 18 18:54:15 2022 +0800
feat:add zentao project extractor
---
plugins/zentao/impl/impl.go | 83 ++++++++-------
plugins/zentao/models/archived/project.go | 113 +++++++++++++++++++++
.../migrationscripts/20220906_add_init_tables.go | 1 +
plugins/zentao/tasks/project_extractor.go | 63 ++++++++++++
4 files changed, 218 insertions(+), 42 deletions(-)
diff --git a/plugins/zentao/impl/impl.go b/plugins/zentao/impl/impl.go
index cc81c226..f24f6afe 100644
--- a/plugins/zentao/impl/impl.go
+++ b/plugins/zentao/impl/impl.go
@@ -21,11 +21,11 @@ import (
"fmt"
"github.com/apache/incubator-devlake/migration"
"github.com/apache/incubator-devlake/plugins/core"
- "github.com/apache/incubator-devlake/plugins/zentao/api"
- "github.com/apache/incubator-devlake/plugins/zentao/models"
- "github.com/apache/incubator-devlake/plugins/zentao/models/migrationscripts"
- "github.com/apache/incubator-devlake/plugins/zentao/tasks"
"github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/api"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
+ "github.com/apache/incubator-devlake/plugins/zentao/models/migrationscripts"
+ "github.com/apache/incubator-devlake/plugins/zentao/tasks"
"github.com/spf13/viper"
"gorm.io/gorm"
)
@@ -38,8 +38,6 @@ var _ core.PluginApi = (*Zentao)(nil)
var _ core.PluginBlueprintV100 = (*Zentao)(nil)
var _ core.CloseablePluginTask = (*Zentao)(nil)
-
-
type Zentao struct{}
func (plugin Zentao) Description() string {
@@ -55,33 +53,34 @@ func (plugin Zentao) SubTaskMetas() []core.SubTaskMeta {
// TODO add your sub task here
return []core.SubTaskMeta{
tasks.CollectProjectMeta,
+ tasks.ExtractProjectsMeta,
}
}
func (plugin Zentao) PrepareTaskData(taskCtx core.TaskContext, options map[string]interface{}) (interface{}, error) {
op, err := tasks.DecodeAndValidateTaskOptions(options)
- if err != nil {
- return nil, err
- }
- connectionHelper := helper.NewConnectionHelper(
- taskCtx,
- nil,
- )
- connection := &models.ZentaoConnection{}
- err = connectionHelper.FirstById(connection, op.ConnectionId)
- if err != nil {
- return nil, fmt.Errorf("unable to get Zentao connection by the given connection ID: %v", err)
- }
-
- apiClient, err := tasks.NewZentaoApiClient(taskCtx, connection)
- if err != nil {
- return nil, fmt.Errorf("unable to get Zentao API client instance: %v", err)
- }
-
- return &tasks.ZentaoTaskData{
- Options: op,
- ApiClient: apiClient,
- }, nil
+ if err != nil {
+ return nil, err
+ }
+ connectionHelper := helper.NewConnectionHelper(
+ taskCtx,
+ nil,
+ )
+ connection := &models.ZentaoConnection{}
+ err = connectionHelper.FirstById(connection, op.ConnectionId)
+ if err != nil {
+ return nil, fmt.Errorf("unable to get Zentao connection by the given connection ID: %v", err)
+ }
+
+ apiClient, err := tasks.NewZentaoApiClient(taskCtx, connection)
+ if err != nil {
+ return nil, fmt.Errorf("unable to get Zentao API client instance: %v", err)
+ }
+
+ return &tasks.ZentaoTaskData{
+ Options: op,
+ ApiClient: apiClient,
+ }, nil
}
// PkgPath information lost when compiled as plugin(.so)
@@ -94,20 +93,20 @@ func (plugin Zentao) MigrationScripts() []migration.Script {
}
func (plugin Zentao) ApiResources() map[string]map[string]core.ApiResourceHandler {
- return map[string]map[string]core.ApiResourceHandler{
- "test": {
- "POST": api.TestConnection,
- },
- "connections": {
- "POST": api.PostConnections,
- "GET": api.ListConnections,
- },
- "connections/:connectionId": {
- "GET": api.GetConnection,
- "PATCH": api.PatchConnection,
- "DELETE": api.DeleteConnection,
- },
- }
+ return map[string]map[string]core.ApiResourceHandler{
+ "test": {
+ "POST": api.TestConnection,
+ },
+ "connections": {
+ "POST": api.PostConnections,
+ "GET": api.ListConnections,
+ },
+ "connections/:connectionId": {
+ "GET": api.GetConnection,
+ "PATCH": api.PatchConnection,
+ "DELETE": api.DeleteConnection,
+ },
+ }
}
func (plugin Zentao) MakePipelinePlan(connectionId uint64, scope []*core.BlueprintScopeV100) (core.PipelinePlan, error) {
diff --git a/plugins/zentao/models/archived/project.go b/plugins/zentao/models/archived/project.go
new file mode 100644
index 00000000..db79cceb
--- /dev/null
+++ b/plugins/zentao/models/archived/project.go
@@ -0,0 +1,113 @@
+/*
+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 archived
+
+import (
+ "github.com/apache/incubator-devlake/models/common"
+ "time"
+)
+
+type ZentaoProject struct {
+ common.NoPKModel
+ ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
+ ID int `json:"id"`
+ Project int `json:"project"`
+ Model string `json:"model"`
+ Type string `json:"type"`
+ Lifetime string `json:"lifetime"`
+ Budget string `json:"budget"`
+ BudgetUnit string `json:"budgetUnit"`
+ Attribute string `json:"attribute"`
+ Percent int `json:"percent"`
+ Milestone string `json:"milestone"`
+ Output string `json:"output"`
+ Auth string `json:"auth"`
+ Parent int `json:"parent"`
+ Path string `json:"path"`
+ Grade int `json:"grade"`
+ Name string `json:"name"`
+ Code string `json:"code"`
+ Begin string `json:"begin"`
+ End string `json:"end"`
+ RealBegan string `json:"realBegan"`
+ RealEnd string `json:"realEnd"`
+ Days int `json:"days"`
+ Status string `json:"status"`
+ SubStatus string `json:"subStatus"`
+ Pri string `json:"pri"`
+ Desc string `json:"desc"`
+ Version int `json:"version"`
+ ParentVersion int `json:"parentVersion"`
+ PlanDuration int `json:"planDuration"`
+ RealDuration int `json:"realDuration"`
+ //OpenedBy string `json:"openedBy"`
+ OpenedDate time.Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
+ LastEditedBy string `json:"lastEditedBy"`
+ LastEditedDate time.Time `json:"lastEditedDate"`
+ //ClosedBy string `json:"closedBy"`
+ //ClosedDate string `json:"closedDate"`
+ //CanceledBy string `json:"canceledBy"`
+ //CanceledDate string `json:"canceledDate"`
+ SuspendedDate string `json:"suspendedDate"`
+ PO string `json:"PO"`
+ PM `json:"PM"`
+ QD string `json:"QD"`
+ RD string `json:"RD"`
+ Team string `json:"team"`
+ Acl string `json:"acl"`
+ Whitelist `json:"whitelist" gorm:"-"`
+ Order int `json:"order"`
+ Vision string `json:"vision"`
+ DisplayCards int `json:"displayCards"`
+ FluidBoard string `json:"fluidBoard"`
+ Deleted bool `json:"deleted"`
+ Delay int `json:"delay"`
+ Hours `json:"hours"`
+ TeamCount int `json:"teamCount"`
+ LeftTasks string `json:"leftTasks"`
+ //TeamMembers []interface{} `json:"teamMembers" gorm:"-"`
+ TotalEstimate int `json:"totalEstimate"`
+ TotalConsumed int `json:"totalConsumed"`
+ TotalLeft int `json:"totalLeft"`
+ Progress int `json:"progress"`
+ TotalReal int `json:"totalReal"`
+}
+type PM struct {
+ PmId int `json:"id"`
+ PmAccount string `json:"account"`
+ PmAvatar string `json:"avatar"`
+ PmRealname string `json:"realname"`
+}
+type Whitelist []struct {
+ WhitelistID int `json:"id"`
+ WhitelistAccount string `json:"account"`
+ WhitelistAvatar string `json:"avatar"`
+ WhitelistRealname string `json:"realname"`
+}
+type Hours struct {
+ HoursTotalEstimate int `json:"totalEstimate"`
+ HoursTotalConsumed int `json:"totalConsumed"`
+ HoursTotalLeft int `json:"totalLeft"`
+ HoursProgress int `json:"progress"`
+ HoursTotalReal int `json:"totalReal"`
+}
+
+func (ZentaoProject) TableName() string {
+ return "_tool_zentao_project"
+}
diff --git a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
index fa9f9684..1a743c46 100644
--- a/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
+++ b/plugins/zentao/models/migrationscripts/20220906_add_init_tables.go
@@ -28,6 +28,7 @@ type addInitTables struct{}
func (u *addInitTables) Up(ctx context.Context, db *gorm.DB) error {
return db.Migrator().AutoMigrate(
archived.ZentaoConnection{},
+ archived.ZentaoProject{},
)
}
diff --git a/plugins/zentao/tasks/project_extractor.go b/plugins/zentao/tasks/project_extractor.go
new file mode 100644
index 00000000..6cc9d9e5
--- /dev/null
+++ b/plugins/zentao/tasks/project_extractor.go
@@ -0,0 +1,63 @@
+/*
+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 (
+ "encoding/json"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "github.com/apache/incubator-devlake/plugins/zentao/models/archived"
+)
+
+var _ core.SubTaskEntryPoint = ExtractProjects
+
+var ExtractProjectsMeta = core.SubTaskMeta{
+ Name: "extractProjects",
+ EntryPoint: ExtractProjects,
+ EnabledByDefault: true,
+ Description: "extract Zentao projects",
+ DomainTypes: []string{core.DOMAIN_TYPE_TICKET},
+}
+
+func ExtractProjects(taskCtx core.SubTaskContext) error {
+ data := taskCtx.GetData().(*ZentaoTaskData)
+ extractor, err := helper.NewApiExtractor(helper.ApiExtractorArgs{
+ RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
+ Ctx: taskCtx,
+ Params: ZentaoApiParams{},
+ Table: RAW_PROJECT_TABLE,
+ },
+ Extract: func(row *helper.RawData) ([]interface{}, error) {
+ project := &archived.ZentaoProject{}
+ err := json.Unmarshal(row.Data, project)
+ if err != nil {
+ return nil, err
+ }
+ project.ConnectionId = data.Options.ConnectionId
+ results := make([]interface{}, 0)
+ results = append(results, project)
+ return results, nil
+ },
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return extractor.Execute()
+}
[incubator-devlake] 06/12: fix(zentao): fix minor issues
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit f0bd0762c859b6718fae97d1f3cb8945cffa6959
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Sun Sep 18 21:40:57 2022 +0800
fix(zentao): fix minor issues
---
plugins/zentao/models/archived/project.go | 54 ++++++++++++-------------
plugins/zentao/models/{archived => }/project.go | 52 ++++++++++++------------
plugins/zentao/tasks/project_extractor.go | 4 +-
3 files changed, 55 insertions(+), 55 deletions(-)
diff --git a/plugins/zentao/models/archived/project.go b/plugins/zentao/models/archived/project.go
index db79cceb..63c498dd 100644
--- a/plugins/zentao/models/archived/project.go
+++ b/plugins/zentao/models/archived/project.go
@@ -18,12 +18,12 @@ limitations under the License.
package archived
import (
- "github.com/apache/incubator-devlake/models/common"
+ "github.com/apache/incubator-devlake/models/migrationscripts/archived"
"time"
)
type ZentaoProject struct {
- common.NoPKModel
+ archived.NoPKModel
ConnectionId uint64 `gorm:"primaryKey;type:BIGINT NOT NULL"`
ID int `json:"id"`
Project int `json:"project"`
@@ -56,31 +56,31 @@ type ZentaoProject struct {
PlanDuration int `json:"planDuration"`
RealDuration int `json:"realDuration"`
//OpenedBy string `json:"openedBy"`
- OpenedDate time.Time `json:"openedDate"`
- OpenedVersion string `json:"openedVersion"`
- LastEditedBy string `json:"lastEditedBy"`
- LastEditedDate time.Time `json:"lastEditedDate"`
- //ClosedBy string `json:"closedBy"`
- //ClosedDate string `json:"closedDate"`
- //CanceledBy string `json:"canceledBy"`
- //CanceledDate string `json:"canceledDate"`
- SuspendedDate string `json:"suspendedDate"`
- PO string `json:"PO"`
- PM `json:"PM"`
- QD string `json:"QD"`
- RD string `json:"RD"`
- Team string `json:"team"`
- Acl string `json:"acl"`
- Whitelist `json:"whitelist" gorm:"-"`
- Order int `json:"order"`
- Vision string `json:"vision"`
- DisplayCards int `json:"displayCards"`
- FluidBoard string `json:"fluidBoard"`
- Deleted bool `json:"deleted"`
- Delay int `json:"delay"`
- Hours `json:"hours"`
- TeamCount int `json:"teamCount"`
- LeftTasks string `json:"leftTasks"`
+ OpenedDate time.Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
+ LastEditedBy string `json:"lastEditedBy"`
+ LastEditedDate *time.Time `json:"lastEditedDate"`
+ ClosedBy string `json:"closedBy"`
+ ClosedDate *time.Time `json:"closedDate"`
+ CanceledBy string `json:"canceledBy"`
+ CanceledDate *time.Time `json:"canceledDate"`
+ SuspendedDate string `json:"suspendedDate"`
+ PO string `json:"PO"`
+ PM `json:"PM"`
+ QD string `json:"QD"`
+ RD string `json:"RD"`
+ Team string `json:"team"`
+ Acl string `json:"acl"`
+ Whitelist `json:"whitelist" gorm:"-"`
+ Order int `json:"order"`
+ Vision string `json:"vision"`
+ DisplayCards int `json:"displayCards"`
+ FluidBoard string `json:"fluidBoard"`
+ Deleted bool `json:"deleted"`
+ Delay int `json:"delay"`
+ Hours `json:"hours"`
+ TeamCount int `json:"teamCount"`
+ LeftTasks string `json:"leftTasks"`
//TeamMembers []interface{} `json:"teamMembers" gorm:"-"`
TotalEstimate int `json:"totalEstimate"`
TotalConsumed int `json:"totalConsumed"`
diff --git a/plugins/zentao/models/archived/project.go b/plugins/zentao/models/project.go
similarity index 73%
copy from plugins/zentao/models/archived/project.go
copy to plugins/zentao/models/project.go
index db79cceb..5a51d738 100644
--- a/plugins/zentao/models/archived/project.go
+++ b/plugins/zentao/models/project.go
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-package archived
+package models
import (
"github.com/apache/incubator-devlake/models/common"
@@ -56,31 +56,31 @@ type ZentaoProject struct {
PlanDuration int `json:"planDuration"`
RealDuration int `json:"realDuration"`
//OpenedBy string `json:"openedBy"`
- OpenedDate time.Time `json:"openedDate"`
- OpenedVersion string `json:"openedVersion"`
- LastEditedBy string `json:"lastEditedBy"`
- LastEditedDate time.Time `json:"lastEditedDate"`
- //ClosedBy string `json:"closedBy"`
- //ClosedDate string `json:"closedDate"`
- //CanceledBy string `json:"canceledBy"`
- //CanceledDate string `json:"canceledDate"`
- SuspendedDate string `json:"suspendedDate"`
- PO string `json:"PO"`
- PM `json:"PM"`
- QD string `json:"QD"`
- RD string `json:"RD"`
- Team string `json:"team"`
- Acl string `json:"acl"`
- Whitelist `json:"whitelist" gorm:"-"`
- Order int `json:"order"`
- Vision string `json:"vision"`
- DisplayCards int `json:"displayCards"`
- FluidBoard string `json:"fluidBoard"`
- Deleted bool `json:"deleted"`
- Delay int `json:"delay"`
- Hours `json:"hours"`
- TeamCount int `json:"teamCount"`
- LeftTasks string `json:"leftTasks"`
+ OpenedDate time.Time `json:"openedDate"`
+ OpenedVersion string `json:"openedVersion"`
+ LastEditedBy string `json:"lastEditedBy"`
+ LastEditedDate *time.Time `json:"lastEditedDate,string"`
+ ClosedBy string `json:"closedBy"`
+ ClosedDate *time.Time `json:"closedDate,string"`
+ CanceledBy string `json:"canceledBy"`
+ CanceledDate *time.Time `json:"canceledDate,string"`
+ SuspendedDate string `json:"suspendedDate"`
+ PO string `json:"PO"`
+ PM `json:"PM"`
+ QD string `json:"QD"`
+ RD string `json:"RD"`
+ Team string `json:"team"`
+ Acl string `json:"acl"`
+ Whitelist `json:"whitelist" gorm:"-"`
+ Order int `json:"order"`
+ Vision string `json:"vision"`
+ DisplayCards int `json:"displayCards"`
+ FluidBoard string `json:"fluidBoard"`
+ Deleted bool `json:"deleted"`
+ Delay int `json:"delay"`
+ Hours `json:"hours"`
+ TeamCount int `json:"teamCount"`
+ LeftTasks string `json:"leftTasks"`
//TeamMembers []interface{} `json:"teamMembers" gorm:"-"`
TotalEstimate int `json:"totalEstimate"`
TotalConsumed int `json:"totalConsumed"`
diff --git a/plugins/zentao/tasks/project_extractor.go b/plugins/zentao/tasks/project_extractor.go
index 6cc9d9e5..a1388efa 100644
--- a/plugins/zentao/tasks/project_extractor.go
+++ b/plugins/zentao/tasks/project_extractor.go
@@ -21,7 +21,7 @@ import (
"encoding/json"
"github.com/apache/incubator-devlake/plugins/core"
"github.com/apache/incubator-devlake/plugins/helper"
- "github.com/apache/incubator-devlake/plugins/zentao/models/archived"
+ "github.com/apache/incubator-devlake/plugins/zentao/models"
)
var _ core.SubTaskEntryPoint = ExtractProjects
@@ -43,7 +43,7 @@ func ExtractProjects(taskCtx core.SubTaskContext) error {
Table: RAW_PROJECT_TABLE,
},
Extract: func(row *helper.RawData) ([]interface{}, error) {
- project := &archived.ZentaoProject{}
+ project := &models.ZentaoProject{}
err := json.Unmarshal(row.Data, project)
if err != nil {
return nil, err
[incubator-devlake] 02/12: feat(zentao): create new plugin
Posted by wa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch feat-plugin-zentao
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit 74f74a8485479f794fbd89eda52c9059767cae94
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Tue Sep 6 18:03:04 2022 +0800
feat(zentao): create new plugin
Relate to #2961
---
plugins/zentao/api/connection.go | 11 +++++------
plugins/zentao/models/access_token.go | 27 +++++++++++++++++++++++++++
plugins/zentao/tasks/api_client.go | 13 ++++++-------
3 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/plugins/zentao/api/connection.go b/plugins/zentao/api/connection.go
index 2f8183d5..fe702185 100644
--- a/plugins/zentao/api/connection.go
+++ b/plugins/zentao/api/connection.go
@@ -21,7 +21,6 @@ import (
"context"
"github.com/apache/incubator-devlake/errors"
"github.com/apache/incubator-devlake/plugins/core"
- "github.com/apache/incubator-devlake/plugins/feishu/apimodels"
"github.com/apache/incubator-devlake/plugins/helper"
"github.com/apache/incubator-devlake/plugins/zentao/models"
"github.com/mitchellh/mapstructure"
@@ -47,20 +46,20 @@ func TestConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, erro
}
// request for access token
- tokenReqBody := &apimodels.ApiAccessTokenRequest{
- AppId: params.Username,
- AppSecret: params.Password,
+ tokenReqBody := &models.ApiAccessTokenRequest{
+ Account: params.Username,
+ Password: params.Password,
}
tokenRes, err := authApiClient.Post("/tokens", nil, tokenReqBody, nil)
if err != nil {
return nil, err
}
- tokenResBody := &apimodels.ApiAccessTokenResponse{}
+ tokenResBody := &models.ApiAccessTokenResponse{}
err = helper.UnmarshalResponse(tokenRes, tokenResBody)
if err != nil {
return nil, err
}
- if tokenResBody.AppAccessToken == "" && tokenResBody.TenantAccessToken == "" {
+ if tokenResBody.Token == "" {
return nil, errors.Default.New("failed to request access token")
}
diff --git a/plugins/zentao/models/access_token.go b/plugins/zentao/models/access_token.go
new file mode 100644
index 00000000..60bf2617
--- /dev/null
+++ b/plugins/zentao/models/access_token.go
@@ -0,0 +1,27 @@
+/*
+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 models
+
+type ApiAccessTokenRequest struct {
+ Account string `json:"account"`
+ Password string `json:"password"`
+}
+
+type ApiAccessTokenResponse struct {
+ Token string `json:"token"`
+}
diff --git a/plugins/zentao/tasks/api_client.go b/plugins/zentao/tasks/api_client.go
index 62d2d954..17d490fb 100644
--- a/plugins/zentao/tasks/api_client.go
+++ b/plugins/zentao/tasks/api_client.go
@@ -20,7 +20,6 @@ package tasks
import (
"fmt"
"github.com/apache/incubator-devlake/errors"
- "github.com/apache/incubator-devlake/plugins/feishu/apimodels"
"net/http"
"strconv"
"time"
@@ -37,20 +36,20 @@ func NewZentaoApiClient(taskCtx core.TaskContext, connection *models.ZentaoConne
}
// request for access token
- tokenReqBody := &apimodels.ApiAccessTokenRequest{
- AppId: connection.Username,
- AppSecret: connection.Password,
+ tokenReqBody := &models.ApiAccessTokenRequest{
+ Account: connection.Username,
+ Password: connection.Password,
}
tokenRes, err := authApiClient.Post("/tokens", nil, tokenReqBody, nil)
if err != nil {
return nil, err
}
- tokenResBody := &apimodels.ApiAccessTokenResponse{}
+ tokenResBody := &models.ApiAccessTokenResponse{}
err = helper.UnmarshalResponse(tokenRes, tokenResBody)
if err != nil {
return nil, err
}
- if tokenResBody.AppAccessToken == "" && tokenResBody.TenantAccessToken == "" {
+ if tokenResBody.Token == "" {
return nil, errors.Default.New("failed to request access token")
}
// real request apiClient
@@ -60,7 +59,7 @@ func NewZentaoApiClient(taskCtx core.TaskContext, connection *models.ZentaoConne
}
// set token
apiClient.SetHeaders(map[string]string{
- "Token": fmt.Sprintf("%v", tokenResBody.TenantAccessToken),
+ "Token": fmt.Sprintf("%v", tokenResBody.Token),
})
// create rate limit calculator