You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ab...@apache.org on 2023/09/04 08:05:20 UTC

[incubator-devlake] 02/09: update sprint's url field (#5970)

This is an automated email from the ASF dual-hosted git repository.

abeizn pushed a commit to branch feat#5841
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git

commit 65c2b9623951a26496a6cd7f65c5f081744625ae
Author: Lynwee <li...@merico.dev>
AuthorDate: Wed Aug 30 19:34:25 2023 +0800

    update sprint's url field (#5970)
    
    * fix(zentao): fix zentao projects's url, add possible prefix
    
    * fix(zentao): fix sprint's url field
    
    * fix(zentao): fix e2e test
    
    * fix(zentao): fix e2e test
    
    * fix(zentao): remove test zentao system's url
    
    * fix(zentao): fix e2e test error
---
 backend/core/runner/basic_res.go                   |  2 +-
 backend/go.mod                                     |  4 --
 backend/go.sum                                     | 11 ------
 backend/plugins/zentao/e2e/account_test.go         | 21 ++++++++++-
 backend/plugins/zentao/e2e/bug_commits_test.go     |  1 +
 backend/plugins/zentao/e2e/bug_test.go             |  1 +
 backend/plugins/zentao/e2e/changelog_test.go       |  7 ++--
 backend/plugins/zentao/e2e/execution_test.go       |  1 +
 .../e2e/snapshot_tables/execution_sprint.csv       |  4 +-
 backend/plugins/zentao/e2e/story_commits_test.go   |  1 +
 backend/plugins/zentao/e2e/story_test.go           |  1 +
 backend/plugins/zentao/e2e/task_commits_test.go    |  1 +
 backend/plugins/zentao/e2e/task_test.go            |  1 +
 .../plugins/zentao/tasks/execution_convertor.go    | 11 +++++-
 backend/plugins/zentao/tasks/project_convertor.go  | 20 +++-------
 backend/plugins/zentao/tasks/shared.go             | 16 ++++++++
 backend/plugins/zentao/tasks/shared_test.go        | 43 ++++++++++++++++++++++
 17 files changed, 108 insertions(+), 38 deletions(-)

diff --git a/backend/core/runner/basic_res.go b/backend/core/runner/basic_res.go
index a4c930ae9..7694d134d 100644
--- a/backend/core/runner/basic_res.go
+++ b/backend/core/runner/basic_res.go
@@ -33,7 +33,7 @@ import (
 var app_lock sync.Mutex
 var app_inited bool
 
-// CreateAppBasicRes returns a application level BasicRes instance based on .env/environment variables
+// CreateAppBasicRes returns an application level BasicRes instance based on .env/environment variables
 // it is useful because multiple places need BasicRes including `main.go` `directrun` and `worker`
 // keep in mind this function can be called only once
 func CreateAppBasicRes() context.BasicRes {
diff --git a/backend/go.mod b/backend/go.mod
index 2e62a878e..46e741447 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -30,7 +30,6 @@ require (
 	github.com/swaggo/swag v1.16.1
 	github.com/tidwall/gjson v1.14.3
 	github.com/viant/afs v1.16.0
-	github.com/x-cray/logrus-prefixed-formatter v0.5.2
 	go.temporal.io/api v1.7.1-0.20220223032354-6e6fe738916a
 	go.temporal.io/sdk v1.14.0
 	golang.org/x/crypto v0.9.0
@@ -91,9 +90,7 @@ require (
 	github.com/kr/text v0.2.0 // indirect
 	github.com/leodido/go-urn v1.2.4 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
-	github.com/mattn/go-colorable v0.1.11 // indirect
 	github.com/mattn/go-isatty v0.0.19 // indirect
-	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -118,7 +115,6 @@ require (
 	golang.org/x/arch v0.3.0 // indirect
 	golang.org/x/net v0.10.0 // indirect
 	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/term v0.8.0 // indirect
 	golang.org/x/text v0.9.0 // indirect
 	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
 	golang.org/x/tools v0.9.3 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index 922a3a2e8..9312912a2 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -485,7 +485,6 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
 github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -504,8 +503,6 @@ github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQ
 github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
 github.com/merico-dev/graphql v0.0.0-20221027131946-77460a1fd4cd h1:hGQXd4a72JSFIZE+ZVkH5ivE925PGogjob6stgc2too=
 github.com/merico-dev/graphql v0.0.0-20221027131946-77460a1fd4cd/go.mod h1:dcDqG8HXVtfEhTCipFMa0Q+RTKTtDKIO2vJt+JVzHEQ=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
-github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
 github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -535,15 +532,12 @@ github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7
 github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
 github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/panjf2000/ants/v2 v2.4.6 h1:drmj9mcygn2gawZ155dRbo+NfXEfAssjZNU1qoIb4gQ=
@@ -671,8 +665,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
 github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
 github.com/viant/afs v1.16.0 h1:yb9TQ1gjVVLji9lcXLWaarklqmGWeXTZOwc2fwJevCI=
 github.com/viant/afs v1.16.0/go.mod h1:wdiEDffZKJwj1ZSFasy7hHoxLQdSpFZkd3XOWNt1aN0=
-github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
-github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
 github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
 github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -937,7 +929,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1024,7 +1015,6 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -1156,7 +1146,6 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
 gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
diff --git a/backend/plugins/zentao/e2e/account_test.go b/backend/plugins/zentao/e2e/account_test.go
index 4204ee713..04ec31a6f 100644
--- a/backend/plugins/zentao/e2e/account_test.go
+++ b/backend/plugins/zentao/e2e/account_test.go
@@ -18,16 +18,32 @@ limitations under the License.
 package e2e
 
 import (
-	"testing"
-
+	gocontext "context"
 	"github.com/apache/incubator-devlake/core/models/common"
 	"github.com/apache/incubator-devlake/core/models/domainlayer/crossdomain"
+	"github.com/apache/incubator-devlake/core/runner"
 	"github.com/apache/incubator-devlake/helpers/e2ehelper"
+	helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
 	"github.com/apache/incubator-devlake/plugins/zentao/impl"
 	"github.com/apache/incubator-devlake/plugins/zentao/models"
 	"github.com/apache/incubator-devlake/plugins/zentao/tasks"
+	"testing"
+	"time"
 )
 
+var basicContext = runner.CreateAppBasicRes()
+
+func getFakeAPIClient() *helper.ApiAsyncClient {
+	client, _ := helper.NewApiClient(gocontext.Background(),
+		"https://zentao.demo.haogs.cn/api.php/v1/",
+		nil, time.Second*5, "",
+		basicContext,
+	)
+	return &helper.ApiAsyncClient{
+		ApiClient: client,
+	}
+}
+
 func TestZentaoAccountDataFlow(t *testing.T) {
 
 	var zentao impl.Zentao
@@ -39,6 +55,7 @@ func TestZentaoAccountDataFlow(t *testing.T) {
 			ProjectId:    3,
 		},
 		AccountCache: tasks.NewAccountCache(dataflowTester.Dal, 1),
+		ApiClient:    getFakeAPIClient(),
 	}
 
 	// import raw data table
diff --git a/backend/plugins/zentao/e2e/bug_commits_test.go b/backend/plugins/zentao/e2e/bug_commits_test.go
index cc72f1021..0b5ab4b0e 100644
--- a/backend/plugins/zentao/e2e/bug_commits_test.go
+++ b/backend/plugins/zentao/e2e/bug_commits_test.go
@@ -38,6 +38,7 @@ func TestZentaoBugCommitsDataFlow(t *testing.T) {
 			ConnectionId: 1,
 			ProjectId:    22,
 		},
+		ApiClient: getFakeAPIClient(),
 	}
 
 	// import _raw_zentao_api_bug_commits raw data table
diff --git a/backend/plugins/zentao/e2e/bug_test.go b/backend/plugins/zentao/e2e/bug_test.go
index c1397d408..cc8f16896 100644
--- a/backend/plugins/zentao/e2e/bug_test.go
+++ b/backend/plugins/zentao/e2e/bug_test.go
@@ -48,6 +48,7 @@ func TestZentaoBugDataFlow(t *testing.T) {
 		},
 		Bugs:         map[int64]struct{}{},
 		AccountCache: tasks.NewAccountCache(dataflowTester.Dal, 1),
+		ApiClient:    getFakeAPIClient(),
 	}
 
 	// import raw data table
diff --git a/backend/plugins/zentao/e2e/changelog_test.go b/backend/plugins/zentao/e2e/changelog_test.go
index bd52b6603..b0d38ed40 100644
--- a/backend/plugins/zentao/e2e/changelog_test.go
+++ b/backend/plugins/zentao/e2e/changelog_test.go
@@ -43,9 +43,10 @@ func TestZentaoDbGetDataFlow(t *testing.T) {
 			ConnectionId: 1,
 			ProjectId:    0,
 		},
-		Stories: map[int64]struct{}{},
-		Tasks:   map[int64]struct{}{10: {}, 11: {}, 14: {}},
-		Bugs:    map[int64]struct{}{1: {}, 2: {}, 3: {}, 4: {}},
+		Stories:   map[int64]struct{}{},
+		Tasks:     map[int64]struct{}{10: {}, 11: {}, 14: {}},
+		Bugs:      map[int64]struct{}{1: {}, 2: {}, 3: {}, 4: {}},
+		ApiClient: getFakeAPIClient(),
 	}
 
 	dataflowTester.ImportCsvIntoTabler("./raw_tables/zt_action.csv", models.ZentaoRemoteDbAction{})
diff --git a/backend/plugins/zentao/e2e/execution_test.go b/backend/plugins/zentao/e2e/execution_test.go
index 908d2ac5a..8fa7f8658 100644
--- a/backend/plugins/zentao/e2e/execution_test.go
+++ b/backend/plugins/zentao/e2e/execution_test.go
@@ -38,6 +38,7 @@ func TestZentaoExecutionDataFlow(t *testing.T) {
 			ConnectionId: 1,
 			ProjectId:    1,
 		},
+		ApiClient: getFakeAPIClient(),
 	}
 
 	// import raw data table
diff --git a/backend/plugins/zentao/e2e/snapshot_tables/execution_sprint.csv b/backend/plugins/zentao/e2e/snapshot_tables/execution_sprint.csv
index 74bb7e65e..32e8e2b1b 100644
--- a/backend/plugins/zentao/e2e/snapshot_tables/execution_sprint.csv
+++ b/backend/plugins/zentao/e2e/snapshot_tables/execution_sprint.csv
@@ -1,3 +1,3 @@
 id,name,url,status,started_date,ended_date,completed_date,original_board_id
-zentao:ZentaoExecution:1:1,企业网站第一期,",7,1,",ACTIVE,,2022-06-01T00:00:00.000+00:00,,zentao:ZentaoProject:1:1
-zentao:ZentaoExecution:1:12,TR5,",1091,12,",CLOSED,2022-07-07T00:00:00.000+00:00,2022-11-03T00:00:00.000+00:00,,zentao:ZentaoProject:1:1
+zentao:ZentaoExecution:1:1,企业网站第一期,https://zentao.demo.haogs.cn/execution-view-1.html,ACTIVE,,2022-06-01T00:00:00.000+00:00,,zentao:ZentaoProject:1:1
+zentao:ZentaoExecution:1:12,TR5,https://zentao.demo.haogs.cn/execution-view-12.html,CLOSED,2022-07-07T00:00:00.000+00:00,2022-11-03T00:00:00.000+00:00,,zentao:ZentaoProject:1:1
diff --git a/backend/plugins/zentao/e2e/story_commits_test.go b/backend/plugins/zentao/e2e/story_commits_test.go
index 968c46e11..e3932d426 100644
--- a/backend/plugins/zentao/e2e/story_commits_test.go
+++ b/backend/plugins/zentao/e2e/story_commits_test.go
@@ -38,6 +38,7 @@ func TestZentaoStoryCommitsDataFlow(t *testing.T) {
 			ConnectionId: 1,
 			ProjectId:    1,
 		},
+		ApiClient: getFakeAPIClient(),
 	}
 
 	// import _raw_zentao_api_story_commits raw data table
diff --git a/backend/plugins/zentao/e2e/story_test.go b/backend/plugins/zentao/e2e/story_test.go
index c02b8dfcf..baf06e887 100644
--- a/backend/plugins/zentao/e2e/story_test.go
+++ b/backend/plugins/zentao/e2e/story_test.go
@@ -48,6 +48,7 @@ func TestZentaoStoryDataFlow(t *testing.T) {
 		},
 		Stories:      map[int64]struct{}{},
 		AccountCache: tasks.NewAccountCache(dataflowTester.Dal, 1),
+		ApiClient:    getFakeAPIClient(),
 	}
 
 	// import raw data table
diff --git a/backend/plugins/zentao/e2e/task_commits_test.go b/backend/plugins/zentao/e2e/task_commits_test.go
index eb1e79bf5..ff85f961b 100644
--- a/backend/plugins/zentao/e2e/task_commits_test.go
+++ b/backend/plugins/zentao/e2e/task_commits_test.go
@@ -38,6 +38,7 @@ func TestZentaoTaskCommitsDataFlow(t *testing.T) {
 			ConnectionId: 1,
 			ProjectId:    48,
 		},
+		ApiClient: getFakeAPIClient(),
 	}
 
 	// import _raw_zentao_api_task_commits raw data table
diff --git a/backend/plugins/zentao/e2e/task_test.go b/backend/plugins/zentao/e2e/task_test.go
index 79f39cdef..1a2fbbe8d 100644
--- a/backend/plugins/zentao/e2e/task_test.go
+++ b/backend/plugins/zentao/e2e/task_test.go
@@ -51,6 +51,7 @@ func TestZentaoTaskDataFlow(t *testing.T) {
 		},
 		Tasks:        map[int64]struct{}{},
 		AccountCache: tasks.NewAccountCache(dataflowTester.Dal, 1),
+		ApiClient:    getFakeAPIClient(),
 	}
 
 	// import raw data table
diff --git a/backend/plugins/zentao/tasks/execution_convertor.go b/backend/plugins/zentao/tasks/execution_convertor.go
index 9324e8eec..e24225c6d 100644
--- a/backend/plugins/zentao/tasks/execution_convertor.go
+++ b/backend/plugins/zentao/tasks/execution_convertor.go
@@ -18,6 +18,7 @@ limitations under the License.
 package tasks
 
 import (
+	"fmt"
 	"reflect"
 
 	"github.com/apache/incubator-devlake/core/dal"
@@ -43,6 +44,7 @@ var ConvertExecutionMeta = plugin.SubTaskMeta{
 func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error {
 	data := taskCtx.GetData().(*ZentaoTaskData)
 	db := taskCtx.GetDal()
+	logger := taskCtx.GetLogger()
 	executionIdGen := didgen.NewDomainIdGenerator(&models.ZentaoExecution{})
 	projectIdGen := didgen.NewDomainIdGenerator(&models.ZentaoProject{})
 	cursor, err := db.Cursor(
@@ -52,6 +54,12 @@ func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error {
 	if err != nil {
 		return err
 	}
+
+	homePage, getZentaoHomePageErr := getZentaoHomePage(data.ApiClient.GetEndpoint())
+	if getZentaoHomePageErr != nil {
+		logger.Error(getZentaoHomePageErr, "get zentao homepage")
+		return errors.Default.WrapRaw(getZentaoHomePageErr)
+	}
 	defer cursor.Close()
 	convertor, err := api.NewDataConverter(api.DataConverterArgs{
 		InputRowType: reflect.TypeOf(models.ZentaoExecution{}),
@@ -82,13 +90,14 @@ func ConvertExecutions(taskCtx plugin.SubTaskContext) errors.Error {
 					Id: executionIdGen.Generate(toolExecution.ConnectionId, toolExecution.Id),
 				},
 				Name:            toolExecution.Name,
-				Url:             toolExecution.Path,
+				Url:             fmt.Sprintf("%s/execution-view-%d.html", homePage, toolExecution.Id),
 				Status:          domainStatus,
 				StartedDate:     toolExecution.RealBegan.ToNullableTime(),
 				EndedDate:       toolExecution.PlanEnd.ToNullableTime(),
 				CompletedDate:   toolExecution.RealEnd.ToNullableTime(),
 				OriginalBoardID: projectIdGen.Generate(toolExecution.ConnectionId, data.Options.ProjectId),
 			}
+
 			boardSprint := &ticket.BoardSprint{
 				BoardId:  sprint.OriginalBoardID,
 				SprintId: sprint.Id,
diff --git a/backend/plugins/zentao/tasks/project_convertor.go b/backend/plugins/zentao/tasks/project_convertor.go
index 2c392854a..b09ef9405 100644
--- a/backend/plugins/zentao/tasks/project_convertor.go
+++ b/backend/plugins/zentao/tasks/project_convertor.go
@@ -19,9 +19,6 @@ package tasks
 
 import (
 	"fmt"
-	"net/url"
-	"reflect"
-
 	"github.com/apache/incubator-devlake/core/dal"
 	"github.com/apache/incubator-devlake/core/errors"
 	"github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -30,6 +27,7 @@ import (
 	"github.com/apache/incubator-devlake/core/plugin"
 	"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
 	"github.com/apache/incubator-devlake/plugins/zentao/models"
+	"reflect"
 )
 
 const RAW_PROJECT_TABLE = "zentao_api_projects"
@@ -57,16 +55,10 @@ func ConvertProjects(taskCtx plugin.SubTaskContext) errors.Error {
 		return err
 	}
 	defer cursor.Close()
-	var protocol, host string
-	endpoint := data.ApiClient.ApiClient.GetEndpoint()
-	if endpoint != "" {
-		endpointURL, err := url.Parse(endpoint)
-		if err != nil {
-			logger.Error(err, "parse: %s", endpoint)
-		} else {
-			protocol = endpointURL.Scheme
-			host = endpointURL.Host
-		}
+	homePage, getZentaoHomePageErr := getZentaoHomePage(data.ApiClient.GetEndpoint())
+	if getZentaoHomePageErr != nil {
+		logger.Error(getZentaoHomePageErr, "get zentao homepage")
+		return errors.Default.WrapRaw(getZentaoHomePageErr)
 	}
 	convertor, err := api.NewDataConverter(api.DataConverterArgs{
 		InputRowType: reflect.TypeOf(models.ZentaoProject{}),
@@ -87,7 +79,7 @@ func ConvertProjects(taskCtx plugin.SubTaskContext) errors.Error {
 				Description: toolProject.Description,
 				CreatedDate: toolProject.OpenedDate.ToNullableTime(),
 				Type:        "scrum",
-				Url:         fmt.Sprintf("%s://%s/project-index-%d.html", protocol, host, data.Options.ProjectId),
+				Url:         fmt.Sprintf("%s/project-index-%d.html", homePage, data.Options.ProjectId),
 			}
 			results := make([]interface{}, 0)
 			results = append(results, domainBoard)
diff --git a/backend/plugins/zentao/tasks/shared.go b/backend/plugins/zentao/tasks/shared.go
index f02c7f885..158a7709d 100644
--- a/backend/plugins/zentao/tasks/shared.go
+++ b/backend/plugins/zentao/tasks/shared.go
@@ -339,3 +339,19 @@ func extractIdFromLogComment(logCommentType string, comment string) ([]string, e
 	}
 	return ret, nil
 }
+
+// getZentaoHomePage receive endpoint like "http://54.158.1.10:30001/api.php/v1/" and return zentao's homepage like "http://54.158.1.10:30001/"
+func getZentaoHomePage(endpoint string) (string, error) {
+	if endpoint == "" {
+		return "", errors.Default.New("empty endpoint")
+	}
+	endpointURL, err := url.Parse(endpoint)
+	if err != nil {
+		return "", err
+	} else {
+		protocol := endpointURL.Scheme
+		host := endpointURL.Host
+		zentaoPath, _, _ := strings.Cut(endpointURL.Path, "/api.php/v1")
+		return fmt.Sprintf("%s://%s%s", protocol, host, zentaoPath), nil
+	}
+}
diff --git a/backend/plugins/zentao/tasks/shared_test.go b/backend/plugins/zentao/tasks/shared_test.go
index 3dfc5d8eb..3bec1ca23 100644
--- a/backend/plugins/zentao/tasks/shared_test.go
+++ b/backend/plugins/zentao/tasks/shared_test.go
@@ -152,3 +152,46 @@ func Test_extractIdFromLogComment(t *testing.T) {
 		})
 	}
 }
+
+func Test_getZentaoWebURL(t *testing.T) {
+	type args struct {
+		endpoint string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    string
+		wantErr bool
+	}{
+		{
+			name:    "without-zentao",
+			args:    args{endpoint: "http://54.158.1.10:30001/api.php/v1/"},
+			want:    "http://54.158.1.10:30001",
+			wantErr: false,
+		},
+		{
+			name:    "with-zentao",
+			args:    args{endpoint: "http://54.158.1.10:30001/zentao/api.php/v1/"},
+			want:    "http://54.158.1.10:30001/zentao",
+			wantErr: false,
+		},
+		{
+			name:    "with-others",
+			args:    args{endpoint: "http://54.158.1.10:30001/abc/api.php/v1/"},
+			want:    "http://54.158.1.10:30001/abc",
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := getZentaoHomePage(tt.args.endpoint)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("getZentaoHomePage() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got != tt.want {
+				t.Errorf("getZentaoHomePage() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}