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:16 UTC

[incubator-devlake] 08/12: feat(zentao): fix execution time

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()
+}