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

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 68d6725b refactor: rename tasks field from pipeline and move it to 
higher level (#2061)
68d6725b is described below

commit 68d6725be09dcb3e0becfbf6a4655439a9a969b4
Author: abeizn <[email protected]>
AuthorDate: Mon Jun 6 21:45:47 2022 +0800

    refactor: rename tasks field from pipeline and move it to higher level 
(#2061)
    
    * refactor: rename tasks field from pipeline and move it to higher level
    
    * feat(tapd): add story category
    
    closes #2010
    
    * fix: jira apiv2models json value (#2060)
    
    * refactor: rename tasks field from pipeline and move it to higher level
    
    * fix: plugins README
    
    * refactor: rename tasks field from pipeline and move it to higher level
    
    * refactor: rename tasks field from pipeline and move it to higher level
    
    * refactor: rename tasks field from pipeline and move it to higher level
    
    Co-authored-by: Yingchu Chen <[email protected]>
---
 models/migrationscripts/register.go              |  3 +-
 models/migrationscripts/updateSchemas20220601.go | 68 +++++++++++++++++
 models/pipeline.go                               | 23 +++---
 models/task.go                                   |  5 +-
 plugins/ae/ae.go                                 |  2 +-
 plugins/dbt/dbt.go                               |  2 +-
 plugins/feishu/README.md                         | 38 +++++++++-
 plugins/feishu/feishu.go                         |  2 +-
 plugins/gitextractor/README-zh-CN.md             | 45 -----------
 plugins/gitextractor/README.md                   | 58 ++++++++++++++-
 plugins/github/README.md                         | 35 +++++++++
 plugins/github/github.go                         |  2 +-
 plugins/gitlab/README.md                         | 50 ++++++++++++-
 plugins/gitlab/gitlab.go                         | 32 ++++++--
 plugins/jenkins/README.md                        | 50 ++++++++++++-
 plugins/jenkins/jenkins.go                       |  2 +-
 plugins/jira/README.md                           | 66 +++++++++++++++-
 plugins/jira/jira.go                             |  2 +-
 plugins/refdiff/README.md                        | 95 ++++++++++++++++++++++--
 plugins/refdiff/refdiff.go                       |  2 +-
 plugins/tapd/tapd.go                             |  2 +-
 runner/directrun.go                              |  9 ++-
 runner/run_task.go                               | 38 ++++++----
 services/task.go                                 |  6 ++
 24 files changed, 524 insertions(+), 113 deletions(-)

diff --git a/models/migrationscripts/register.go 
b/models/migrationscripts/register.go
index e014cc4e..ebbfcbd7 100644
--- a/models/migrationscripts/register.go
+++ b/models/migrationscripts/register.go
@@ -25,8 +25,7 @@ func RegisterAll() {
                new(initSchemas),
                new(updateSchemas20220505), new(updateSchemas20220507), 
new(updateSchemas20220510),
                new(updateSchemas20220513), new(updateSchemas20220524), 
new(updateSchemas20220526),
-               new(updateSchemas20220527),
-               new(updateSchemas20220528),
+               new(updateSchemas20220527), new(updateSchemas20220528), 
new(updateSchemas20220601),
                new(updateSchemas20220602),
        }, "Framework")
 }
diff --git a/models/migrationscripts/updateSchemas20220601.go 
b/models/migrationscripts/updateSchemas20220601.go
new file mode 100644
index 00000000..55a77d80
--- /dev/null
+++ b/models/migrationscripts/updateSchemas20220601.go
@@ -0,0 +1,68 @@
+/*
+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"
+       "time"
+
+       "github.com/apache/incubator-devlake/models/common"
+       "gorm.io/datatypes"
+       "gorm.io/gorm"
+)
+
+type Task20220601 struct {
+       common.Model
+       Plugin        string         `json:"plugin" gorm:"index"`
+       Subtasks      datatypes.JSON `json:"subtasks"`
+       Options       datatypes.JSON `json:"options"`
+       Status        string         `json:"status"`
+       Message       string         `json:"message"`
+       Progress      float32        `json:"progress"`
+       FailedSubTask string         `json:"failedSubTask"`
+       PipelineId    uint64         `json:"pipelineId" gorm:"index"`
+       PipelineRow   int            `json:"pipelineRow"`
+       PipelineCol   int            `json:"pipelineCol"`
+       BeganAt       *time.Time     `json:"beganAt"`
+       FinishedAt    *time.Time     `json:"finishedAt" gorm:"index"`
+       SpentSeconds  int            `json:"spentSeconds"`
+}
+
+func (Task20220601) TableName() string {
+       return "_devlake_tasks"
+}
+
+type updateSchemas20220601 struct{}
+
+func (*updateSchemas20220601) Up(ctx context.Context, db *gorm.DB) error {
+
+       err := db.Migrator().AddColumn(Task20220601{}, "subtasks")
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (*updateSchemas20220601) Version() uint64 {
+       return 20220601000005
+}
+
+func (*updateSchemas20220601) Name() string {
+       return "add column `subtasks` at _devlake_tasks"
+}
diff --git a/models/pipeline.go b/models/pipeline.go
index da1656b6..6a271ac7 100644
--- a/models/pipeline.go
+++ b/models/pipeline.go
@@ -27,18 +27,17 @@ import (
 
 type Pipeline struct {
        common.Model
-       Name        string         `json:"name" gorm:"index"`
-       BlueprintId uint64         `json:"blueprintId"`
-       Tasks       datatypes.JSON `json:"tasks"`
-       TotalTasks  int            `json:"totalTasks"`
-       // Deprecated
-       FinishedTasks int        `json:"finishedTasks"`
-       BeganAt       *time.Time `json:"beganAt"`
-       FinishedAt    *time.Time `json:"finishedAt" gorm:"index"`
-       Status        string     `json:"status"`
-       Message       string     `json:"message"`
-       SpentSeconds  int        `json:"spentSeconds"`
-       Stage         int        `json:"stage"`
+       Name          string         `json:"name" gorm:"index"`
+       BlueprintId   uint64         `json:"blueprintId"`
+       Tasks         datatypes.JSON `json:"tasks"`
+       TotalTasks    int            `json:"totalTasks"`
+       FinishedTasks int            `json:"finishedTasks"`
+       BeganAt       *time.Time     `json:"beganAt"`
+       FinishedAt    *time.Time     `json:"finishedAt" gorm:"index"`
+       Status        string         `json:"status"`
+       Message       string         `json:"message"`
+       SpentSeconds  int            `json:"spentSeconds"`
+       Stage         int            `json:"stage"`
 }
 
 // We use a 2D array because the request body must be an array of a set of 
tasks
diff --git a/models/task.go b/models/task.go
index 0d77a607..d4e32420 100644
--- a/models/task.go
+++ b/models/task.go
@@ -43,6 +43,7 @@ type TaskProgressDetail struct {
 type Task struct {
        common.Model
        Plugin         string              `json:"plugin" gorm:"index"`
+       Subtasks       datatypes.JSON      `json:"subtasks"`
        Options        datatypes.JSON      `json:"options"`
        Status         string              `json:"status"`
        Message        string              `json:"message"`
@@ -60,8 +61,8 @@ type Task struct {
 
 type NewTask struct {
        // Plugin name
-       Plugin string `json:"plugin" binding:"required"`
-       // Options for the plugin task to be triggered
+       Plugin      string                 `json:"plugin" binding:"required"`
+       Subtasks    []string               `json:"subtasks"`
        Options     map[string]interface{} `json:"options"`
        PipelineId  uint64                 `json:"-"`
        PipelineRow int                    `json:"-"`
diff --git a/plugins/ae/ae.go b/plugins/ae/ae.go
index e2bad02f..f55262c5 100644
--- a/plugins/ae/ae.go
+++ b/plugins/ae/ae.go
@@ -108,7 +108,7 @@ func main() {
        projectId := aeCmd.Flags().IntP("project-id", "p", 0, "ae project id")
        _ = aeCmd.MarkFlagRequired("project-id")
        aeCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "projectId": *projectId,
                })
        }
diff --git a/plugins/dbt/dbt.go b/plugins/dbt/dbt.go
index c3ce3d3e..b0a4be40 100644
--- a/plugins/dbt/dbt.go
+++ b/plugins/dbt/dbt.go
@@ -97,7 +97,7 @@ func main() {
                for k, v := range projectVars {
                        projectVarsConvert[k] = v
                }
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "projectPath":    *projectPath,
                        "projectName":    *projectName,
                        "projectTarget":  *projectTarget,
diff --git a/plugins/feishu/README.md b/plugins/feishu/README.md
index fbeb234b..d5349c60 100644
--- a/plugins/feishu/README.md
+++ b/plugins/feishu/README.md
@@ -32,7 +32,7 @@ FEISHU_APPSCRECT=app_secret
 In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
 numOfDaysToCollect: The number of days you want to collect
 rateLimitPerSecond: The number of requests to send(Maximum is 8)
-
+1. Configure-UI Mode
 ```json
 [
   [
@@ -47,6 +47,23 @@ rateLimitPerSecond: The number of requests to send(Maximum 
is 8)
 ]
 ```
 
+and if you want to perform certain subtasks.
+```
+[
+  [
+    {
+      "plugin": "feishu",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+        "numOfDaysToCollect" : 80,
+        "rateLimitPerSecond" : 5
+      }
+    }
+  ]
+]
+```
+
+2. Curl Mode:
 You can also trigger data collection by making a POST request to `/pipelines`.
 ```
 curl --location --request POST 'localhost:8080/pipelines' \
@@ -63,4 +80,23 @@ curl --location --request POST 'localhost:8080/pipelines' \
     }]]
 }
 '
+```
+
+and if you want to perform certain subtasks.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "feishu 20211126",
+    "tasks": [[{
+      "plugin": "feishu",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+        "numOfDaysToCollect" : 80,
+        "rateLimitPerSecond" : 5
+      }
+    }]]
+}
+'
 ```
\ No newline at end of file
diff --git a/plugins/feishu/feishu.go b/plugins/feishu/feishu.go
index b5a5828f..3b1635d1 100644
--- a/plugins/feishu/feishu.go
+++ b/plugins/feishu/feishu.go
@@ -90,7 +90,7 @@ func main() {
        numOfDaysToCollect := feishuCmd.Flags().IntP("numOfDaysToCollect", "n", 
8, "feishu collect days")
        _ = feishuCmd.MarkFlagRequired("numOfDaysToCollect")
        feishuCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "numOfDaysToCollect": *numOfDaysToCollect,
                })
        }
diff --git a/plugins/gitextractor/README-zh-CN.md 
b/plugins/gitextractor/README-zh-CN.md
deleted file mode 100644
index 20a83b4a..00000000
--- a/plugins/gitextractor/README-zh-CN.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Git Repo Extractor插件
-
-## Summary
-
-该插件可以从远端或本地git仓库提取commit和reference信息,并保存到数据库或csv文件。
-
-## 示例
-
-```
-curl --location --request POST 'localhost:8080/pipelines' \
---header 'Content-Type: application/json' \
---data-raw '
-{
-    "name": "git repo extractor",
-    "tasks": [
-        [
-            {
-                "Plugin": "gitextractor",
-                "Options": {
-                    "url": "https://github.com/apache/incubator-devlake.git";,
-                    "repoId": "github:GithubRepos:384111310"
-                }
-            }
-        ]
-    ]
-}
-'
-```
-- `url`: git仓库的位置,如果是远端仓库应当以`http`或`https`开头, 如果是本地仓库则应当以`/`开头
-- `repoId`: `repos`表的`id`字段.
-- `proxy`: 可选, 只支持`http`代理,例如:`http://your-proxy-server.com:1080`.
-- `user`: 可选, 通过HTTP/HTTPS协议克隆私有代码库时使用
-- `password`: 可选, 通过HTTP/HTTPS协议克隆私有代码库时使用
-- `privateKey`: 可选, 通过SSH协议克隆代码库时使用, 值为经过base64编码的`PEM`文件
-- `passphrase`: 可选, 私钥的密码
-
-## 独立运行本插件
-
-本插件可以作为独立于DevLake服务的命令行工具使用:
-
-```
-go run plugins/gitextractor/main.go -url 
https://github.com/apache/incubator-devlake.git -id github:GithubRepo:384111310 
-db "merico:merico@tcp(127.0.0.1:3306)/lake?charset=utf8mb4&parseTime=True"
-```
-
-如果想了解命令行工具的更多选项,比如如何输出收集结果到csv文件,请直接阅读`plugins/gitextractor/main.go`。
\ No newline at end of file
diff --git a/plugins/gitextractor/README.md b/plugins/gitextractor/README.md
index 5866a899..9c18c416 100644
--- a/plugins/gitextractor/README.md
+++ b/plugins/gitextractor/README.md
@@ -10,7 +10,60 @@ This plugin extract commits and references from a remote or 
local git repository
 3. Use the [RefDiff](../refdiff) plugin to calculate version diff, which will 
be stored in `refs_commits_diffs` table.
 
 ## Sample Request
+1. Configure-UI Mode
+In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
+```
+[
+  [
+    {
+      "Plugin": "gitextractor",
+      "Options": {
+        "url": "https://github.com/apache/incubator-devlake.git";,
+        "repoId": "github:GithubRepo:384111310"
+      }
+    }
+  ]
+]
+```
+and if you want to perform certain subtasks.
+```
+[
+  [
+    {
+      "plugin": "gitextractor",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+        "url": "https://github.com/apache/incubator-devlake.git";,
+        "repoId": "github:GithubRepo:384111310"
+      }
+    }
+  ]
+]
+```
 
+2. Curl Mode:
+You can also trigger data collection by making a POST request to `/pipelines`.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "git repo extractor",
+    "tasks": [
+        [
+            {
+                "plugin": "gitextractor",
+                "options": {
+                    "url": "https://github.com/apache/incubator-devlake.git";,
+                    "repoId": "github:GithubRepo:384111310"
+                }
+            }
+        ]
+    ]
+}
+'
+```
+and if you want to perform certain subtasks.
 ```
 curl --location --request POST 'localhost:8080/pipelines' \
 --header 'Content-Type: application/json' \
@@ -20,8 +73,9 @@ curl --location --request POST 'localhost:8080/pipelines' \
     "tasks": [
         [
             {
-                "Plugin": "gitextractor",
-                "Options": {
+                "plugin": "gitextractor",
+                "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+                "options": {
                     "url": "https://github.com/apache/incubator-devlake.git";,
                     "repoId": "github:GithubRepo:384111310"
                 }
diff --git a/plugins/github/README.md b/plugins/github/README.md
index 0ada072d..0e8660f7 100644
--- a/plugins/github/README.md
+++ b/plugins/github/README.md
@@ -70,6 +70,7 @@ Define regex pattern in .env
 
 ## Sample Request
 In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
+1. Configure-UI Mode
 ```json
 [
   [
@@ -83,7 +84,23 @@ In order to collect data, you have to compose a JSON looks 
like following one, a
   ]
 ]
 ```
+and if you want to perform certain subtasks.
+```json
+[
+  [
+    {
+      "plugin": "github",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+        "repo": "lake",
+        "owner": "merico-dev"
+      }
+    }
+  ]
+]
+```
 
+2. Curl Mode:
 You can also trigger data collection by making a POST request to `/pipelines`.
 ```
 curl --location --request POST 'localhost:8080/pipelines' \
@@ -101,3 +118,21 @@ curl --location --request POST 'localhost:8080/pipelines' \
 }
 '
 ```
+and if you want to perform certain subtasks.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "github 20211126",
+    "tasks": [[{
+        "plugin": "github",
+        "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+        "options": {
+            "repo": "lake",
+            "owner": "merico-dev"
+        }
+    }]]
+}
+'
+```
diff --git a/plugins/github/github.go b/plugins/github/github.go
index 765a4d28..e0806c6f 100644
--- a/plugins/github/github.go
+++ b/plugins/github/github.go
@@ -144,7 +144,7 @@ func main() {
        _ = githubCmd.MarkFlagRequired("repo")
 
        githubCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "owner": *owner,
                        "repo":  *repo,
                })
diff --git a/plugins/gitlab/README.md b/plugins/gitlab/README.md
index 0e99ec2b..01053513 100644
--- a/plugins/gitlab/README.md
+++ b/plugins/gitlab/README.md
@@ -54,9 +54,37 @@ There are no additional settings for the GitLab Datasource 
Provider at this time
 NOTE: `GitLab Project ID` Mappings feature has been deprecated.
 
 ## Gathering Data with Gitlab
+In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
+1. Configure-UI Mode
+```json
+[
+  [
+    {
+      "plugin": "gitlab",
+      "options": {
+        "projectId": <Your gitlab project id>
+      }
+    }
+  ]
+]
+```
+and if you want to perform certain subtasks.
+```json
+[
+  [
+    {
+      "plugin": "gitlab",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+        "projectId": <Your gitlab project id>
+      }
+    }
+  ]
+]
+```
 
-To collect data, you can make a POST request to `/pipelines`
-
+2. Curl Mode:
+You can also trigger data collection by making a POST request to `/pipelines`.
 ```
 curl --location --request POST 'localhost:8080/pipelines' \
 --header 'Content-Type: application/json' \
@@ -72,6 +100,24 @@ curl --location --request POST 'localhost:8080/pipelines' \
 }
 '
 ```
+and if you want to perform certain subtasks.`
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "gitlab 20211126",
+    "tasks": [[{
+        "plugin": "gitlab",
+        "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+        "options": {
+            "projectId": <Your gitlab project id>
+        }
+    }]]
+}
+'
+```
+
 
 ## Finding Project Id
 
diff --git a/plugins/gitlab/gitlab.go b/plugins/gitlab/gitlab.go
index 88ce9f10..7d2be2e5 100644
--- a/plugins/gitlab/gitlab.go
+++ b/plugins/gitlab/gitlab.go
@@ -18,7 +18,10 @@ limitations under the License.
 package main // must be main for plugin entry point
 
 import (
+       "github.com/apache/incubator-devlake/config"
+       "github.com/apache/incubator-devlake/logger"
        "github.com/apache/incubator-devlake/plugins/gitlab/impl"
+       "github.com/apache/incubator-devlake/plugins/tapd/models"
        "github.com/apache/incubator-devlake/runner"
        "github.com/spf13/cobra"
 )
@@ -29,13 +32,28 @@ var PluginEntry impl.Gitlab //nolint
 // standalone mode for debugging
 func main() {
        gitlabCmd := &cobra.Command{Use: "gitlab"}
-       projectId := gitlabCmd.Flags().IntP("project-id", "p", 0, "gitlab 
project id")
-
-       _ = gitlabCmd.MarkFlagRequired("project-id")
-       gitlabCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
-                       "projectId": *projectId,
-               })
+       gitlabCmd.Run = func(c *cobra.Command, args []string) {
+               cfg := config.GetConfig()
+               log := logger.Global.Nested(gitlabCmd.Use)
+               db, err := runner.NewGormDb(cfg, log)
+               if err != nil {
+                       panic(err)
+               }
+               wsList := make([]*models.TapdWorkspace, 0)
+               err = db.Find(&wsList, "parent_id = ?", 59169984).Error
+               projectList := []uint64{63281714,
+                       34276182,
+                       46319043,
+                       50328292,
+                       63984859,
+                       55805854,
+                       38496185,
+               }
+               for _, v := range projectList {
+                       runner.DirectRun(gitlabCmd, args, PluginEntry, 
[]string{}, map[string]interface{}{
+                               "projectId": v,
+                       })
+               }
        }
 
        runner.RunCmd(gitlabCmd)
diff --git a/plugins/jenkins/README.md b/plugins/jenkins/README.md
index dd62e06b..812500bb 100644
--- a/plugins/jenkins/README.md
+++ b/plugins/jenkins/README.md
@@ -44,10 +44,8 @@ The connection aspect of the configuration screen requires 
the following key fie
 Click Save Connection to update connection settings.
 
 ## Collect Data From Jenkins
-
-In order to collect data from Jenkins, you have to compose a JSON looks like 
following one, and send it via `Triggers` page on `config-ui`:
-
-
+In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
+1. Configure-UI Mode
 ```json
 [
   [
@@ -58,6 +56,50 @@ In order to collect data from Jenkins, you have to compose a 
JSON looks like fol
   ]
 ]
 ```
+and if you want to perform certain subtasks.
+```json
+[
+  [
+    {
+      "plugin": "jenkins",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {}
+    }
+  ]
+]
+```
+
+2. Curl Mode:
+You can also trigger data collection by making a POST request to `/pipelines`.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "jenkins 20211126",
+    "tasks": [[{
+        "plugin": "jenkins",
+        "options": {}
+    }]]
+}
+'
+```
+and if you want to perform certain subtasks.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "jenkins 20211126",
+    "tasks": [[{
+        "plugin": "jenkins",
+        "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+        "options": {}
+    }]]
+}
+'
+```
+
 
 ## Relationship between job and build
 
diff --git a/plugins/jenkins/jenkins.go b/plugins/jenkins/jenkins.go
index 4edc89df..b1e2d6a8 100644
--- a/plugins/jenkins/jenkins.go
+++ b/plugins/jenkins/jenkins.go
@@ -102,7 +102,7 @@ var PluginEntry Jenkins //nolint
 func main() {
        jenkinsCmd := &cobra.Command{Use: "jenkins"}
        jenkinsCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, 
map[string]interface{}{})
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{})
        }
        runner.RunCmd(jenkinsCmd)
 }
diff --git a/plugins/jira/README.md b/plugins/jira/README.md
index e9901c9a..6b133d63 100644
--- a/plugins/jira/README.md
+++ b/plugins/jira/README.md
@@ -67,14 +67,75 @@ Please follow this guide: [How to find Jira the custom 
field ID in Jira? · meri
 
 ## Collect Data From JIRA
 
-In order to collect data from JIRA, you have to compose a JSON looks like 
following one, and send it via `Triggers` page on `config-ui`:
+In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
 <font color=“red”>Warning: Data collection only supports single-task 
execution, and the results of concurrent multi-task execution may not meet 
expectations.</font>
 
+1. Configure-UI Mode:
+```json
+[
+  [
+    {
+      "plugin": "jira",
+      "options": {
+          "connectionId": 1,
+          "boardId": 8,
+          "since": "2006-01-02T15:04:05Z"
+      }
+    }
+  ]
+]
 ```
+and if you want to perform certain subtasks.
+```json
 [
   [
     {
       "plugin": "jira",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
+      "options": {
+          "connectionId": 1,
+          "boardId": 8,
+          "since": "2006-01-02T15:04:05Z"
+      }
+    }
+  ]
+]
+```
+
+2. Curl Mode:
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "jenkins 20211126",
+    "tasks": [
+  [
+    {
+      "plugin": "jira",
+      "options": {
+          "connectionId": 1,
+          "boardId": 8,
+          "since": "2006-01-02T15:04:05Z"
+      }
+    }
+  ]
+]
+}
+'
+```
+and if you want to perform certain subtasks.
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "jenkins 20211126",
+    "tasks": [
+  [
+    {
+      "plugin": "jira",
+      "subtasks": ["collectXXX", "extractXXX", "convertXXX"],
       "options": {
           "connectionId": 1,
           "boardId": 8,
@@ -83,8 +144,11 @@ In order to collect data from JIRA, you have to compose a 
JSON looks like follow
     }
   ]
 ]
+}
+'
 ```
 
+
 - `connectionId`: The `ID` field from **JIRA Integration** page.
 - `boardId`: JIRA board id, see [Find Board Id](#find-board-id) for detail.
 - `since`: optional, download data since specified date/time only.
diff --git a/plugins/jira/jira.go b/plugins/jira/jira.go
index 9f758190..2b865ea6 100644
--- a/plugins/jira/jira.go
+++ b/plugins/jira/jira.go
@@ -217,7 +217,7 @@ func main() {
        _ = cmd.MarkFlagRequired("connection")
        _ = cmd.MarkFlagRequired("board")
        cmd.Run = func(c *cobra.Command, args []string) {
-               runner.DirectRun(c, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(c, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "connectionId": *connectionId,
                        "boardId":      *boardId,
                })
diff --git a/plugins/refdiff/README.md b/plugins/refdiff/README.md
index e0e9dca6..01f649e3 100644
--- a/plugins/refdiff/README.md
+++ b/plugins/refdiff/README.md
@@ -37,31 +37,110 @@ github:GithubRepo:384111310:refs/tags/v0.6.1  TAG
 2. If you want to run calculateIssuesDiff, please configure 
GITHUB_PR_BODY_CLOSE_PATTERN in .env, you can check the example in 
.env.example(we have a default value, please make sure your pattern is 
disclosed by single quotes '')
 3. If you want to run calculatePrCherryPick, please configure 
GITHUB_PR_TITLE_PATTERN in .env, you can check the example in .env.example(we 
have a default value, please make sure your pattern is disclosed by single 
quotes '')
 4. And then, trigger a pipeline like following, you can also define sub tasks, 
calculateRefDiff will calculate commits between two ref, and creatRefBugStats 
will create a table to show bug list between two ref:
+   
+In order to collect data, you have to compose a JSON looks like following one, 
and send it by selecting `Advanced Mode` on `Create Pipeline Run` page:
+1. Configure-UI Mode:
+```json
+[
+  [
+    {
+      "plugin": "refdiff",
+      "options": {
+        "repoId": "github:GithubRepo:384111310",
+        "pairs": [
+          {
+            "newRef": "refs/tags/v0.6.0",
+            "oldRef": "refs/tags/0.5.0"
+          },
+          {
+            "newRef": "refs/tags/0.5.0",
+            "oldRef": "refs/tags/0.4.0"
+          }
+        ]
+      }
+    }
+  ]
+]
+```
+and if you want to perform certain subtasks.
+```json
+[
+  [
+    {
+      "plugin": "refdiff",
+      "subtasks": [
+        "calculateCommitsDiff",
+        "calculateIssuesDiff",
+        "calculatePrCherryPick"
+      ],
+      "options": {
+        "repoId": "github:GithubRepo:384111310",
+        "pairs": [
+          {
+            "newRef": "refs/tags/v0.6.0",
+            "oldRef": "refs/tags/0.5.0"
+          },
+          {
+            "newRef": "refs/tags/0.5.0",
+            "oldRef": "refs/tags/0.4.0"
+          }
+        ]
+      }
+    }
+  ]
+]
+```
+
+2. Curl Mode:
+```
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
+{
+    "name": "test-refdiff",
+    "tasks": [
+        [
+            {
+                "plugin": "refdiff",
+                "options": {
+                    "repoId": "github:GithubRepo:384111310",
+                    "pairs": [
+                       { "newRef": "refs/tags/v0.6.0", "oldRef": 
"refs/tags/0.5.0" },
+                       { "newRef": "refs/tags/0.5.0", "oldRef": 
"refs/tags/0.4.0" }
+                    ]
+                }
+            }
+        ]
+    ]
+}'
+```
+and if you want to perform certain subtasks.
 ```
-curl -v -XPOST http://localhost:8080/pipelines --data @- <<'JSON'
+curl --location --request POST 'localhost:8080/pipelines' \
+--header 'Content-Type: application/json' \
+--data-raw '
 {
     "name": "test-refdiff",
     "tasks": [
         [
             {
                 "plugin": "refdiff",
+                "subtasks": [
+                    "calculateCommitsDiff",
+                    "calculateIssuesDiff",
+                    "calculatePrCherryPick"
+                ],
                 "options": {
                     "repoId": "github:GithubRepo:384111310",
                     "pairs": [
                        { "newRef": "refs/tags/v0.6.0", "oldRef": 
"refs/tags/0.5.0" },
                        { "newRef": "refs/tags/0.5.0", "oldRef": 
"refs/tags/0.4.0" }
-                    ],
-                    "tasks": [
-                        "calculateCommitsDiff",
-                        "calculateIssuesDiff",
-                        "calculatePrCherryPick",
                     ]
                 }
             }
         ]
     ]
-}
-JSON
+}'
 ```
 
 ## Development
diff --git a/plugins/refdiff/refdiff.go b/plugins/refdiff/refdiff.go
index 881feab1..b2a2ef44 100644
--- a/plugins/refdiff/refdiff.go
+++ b/plugins/refdiff/refdiff.go
@@ -88,7 +88,7 @@ func main() {
        _ = refdiffCmd.MarkFlagRequired("old-ref")
 
        refdiffCmd.Run = func(cmd *cobra.Command, args []string) {
-               runner.DirectRun(cmd, args, PluginEntry, map[string]interface{}{
+               runner.DirectRun(cmd, args, PluginEntry, []string{}, 
map[string]interface{}{
                        "repoId": repoId,
                        "pairs": []map[string]string{
                                {
diff --git a/plugins/tapd/tapd.go b/plugins/tapd/tapd.go
index e20194be..e7212fa1 100644
--- a/plugins/tapd/tapd.go
+++ b/plugins/tapd/tapd.go
@@ -222,7 +222,7 @@ func main() {
                err = db.Find(&wsList, "parent_id = ?", 59169984).Error
                for _, v := range wsList {
                        *workspaceId = v.ID
-                       runner.DirectRun(c, args, PluginEntry, 
map[string]interface{}{
+                       runner.DirectRun(c, args, PluginEntry, []string{}, 
map[string]interface{}{
                                "connectionId": *connectionId,
                                "workspaceId":  *workspaceId,
                                "companyId":    *companyId,
diff --git a/runner/directrun.go b/runner/directrun.go
index 5e5851e0..6ab5b83d 100644
--- a/runner/directrun.go
+++ b/runner/directrun.go
@@ -30,7 +30,7 @@ import (
 )
 
 func RunCmd(cmd *cobra.Command) {
-       cmd.Flags().StringSliceP("tasks", "t", nil, "specify what tasks to run, 
--tasks=collectIssues,extractIssues")
+       cmd.Flags().StringSliceP("subtasks", "t", nil, "specify what tasks to 
run, --subtasks=collectIssues,extractIssues")
        err := cmd.Execute()
        if err != nil {
                panic(err)
@@ -42,12 +42,12 @@ func RunCmd(cmd *cobra.Command) {
 // args: command line arguments
 // pluginTask: specific built-in plugin, for example: feishu, jira...
 // options: plugin config
-func DirectRun(cmd *cobra.Command, args []string, pluginTask core.PluginTask, 
options map[string]interface{}) {
-       tasks, err := cmd.Flags().GetStringSlice("tasks")
+func DirectRun(cmd *cobra.Command, args []string, pluginTask core.PluginTask, 
subtasks []string, options map[string]interface{}) {
+       tasks, err := cmd.Flags().GetStringSlice("subtasks")
        if err != nil {
                panic(err)
        }
-       options["tasks"] = tasks
+       subtasks = tasks
        cfg := config.GetConfig()
        log := logger.Global.Nested(cmd.Use)
        db, err := NewGormDb(cfg, log)
@@ -102,6 +102,7 @@ func DirectRun(cmd *cobra.Command, args []string, 
pluginTask core.PluginTask, op
                db,
                ctx,
                cmd.Use,
+               subtasks,
                options,
                pluginTask,
                nil,
diff --git a/runner/run_task.go b/runner/run_task.go
index e021b0a0..568d47b6 100644
--- a/runner/run_task.go
+++ b/runner/run_task.go
@@ -101,6 +101,11 @@ func RunTask(
        if err != nil {
                return err
        }
+       var subtasks []string
+       err = json.Unmarshal(task.Subtasks, &subtasks)
+       if err != nil {
+               return err
+       }
 
        err = RunPluginTask(
                config.GetConfig(),
@@ -108,6 +113,7 @@ func RunTask(
                db,
                ctx,
                task.Plugin,
+               subtasks,
                options,
                progress,
        )
@@ -120,6 +126,7 @@ func RunPluginTask(
        db *gorm.DB,
        ctx context.Context,
        name string,
+       subtasks []string,
        options map[string]interface{},
        progress chan core.RunningProgress,
 ) error {
@@ -138,6 +145,7 @@ func RunPluginTask(
                db,
                ctx,
                name,
+               subtasks,
                options,
                pluginTask,
                progress,
@@ -150,6 +158,7 @@ func RunPluginSubTasks(
        db *gorm.DB,
        ctx context.Context,
        name string,
+       subtasks []string,
        options map[string]interface{},
        pluginTask core.PluginTask,
        progress chan core.RunningProgress,
@@ -158,36 +167,35 @@ func RunPluginSubTasks(
 
        // find out all possible subtasks this plugin can offer
        subtaskMetas := pluginTask.SubTaskMetas()
-       subtasks := make(map[string]bool)
+       subtasksFlag := make(map[string]bool)
        for _, subtaskMeta := range subtaskMetas {
-               subtasks[subtaskMeta.Name] = subtaskMeta.EnabledByDefault
+               subtasksFlag[subtaskMeta.Name] = subtaskMeta.EnabledByDefault
        }
-       /* subtasks example
-       subtasks := map[string]bool{
+       /* subtasksFlag example
+       subtasksFlag := map[string]bool{
                "collectProject": true,
                "convertCommits": true,
                ...
        }
        */
 
-       // if user specified what subtasks to run, obey
-       // TODO: move tasks field to outer level, and rename it to subtasks
-       if _, ok := options["tasks"]; ok {
+       // user specifies what subtasks to run
+       if len(subtasks) != 0 {
                // decode user specified subtasks
                var specifiedTasks []string
-               err := mapstructure.Decode(options["tasks"], &specifiedTasks)
+               err := mapstructure.Decode(subtasks, &specifiedTasks)
                if err != nil {
                        return err
                }
                if len(specifiedTasks) > 0 {
                        // first, disable all subtasks
-                       for task := range subtasks {
-                               subtasks[task] = false
+                       for task := range subtasksFlag {
+                               subtasksFlag[task] = false
                        }
                        // second, check specified subtasks is valid and enable 
them if so
                        for _, task := range specifiedTasks {
-                               if _, ok := subtasks[task]; ok {
-                                       subtasks[task] = true
+                               if _, ok := subtasksFlag[task]; ok {
+                                       subtasksFlag[task] = true
                                } else {
                                        return fmt.Errorf("subtask %s does not 
exist", task)
                                }
@@ -197,18 +205,18 @@ func RunPluginSubTasks(
        // make sure `Required` subtasks are always enabled
        for _, subtaskMeta := range subtaskMetas {
                if subtaskMeta.Required {
-                       subtasks[subtaskMeta.Name] = true
+                       subtasksFlag[subtaskMeta.Name] = true
                }
        }
        // calculate total step(number of task to run)
        steps := 0
-       for _, enabled := range subtasks {
+       for _, enabled := range subtasksFlag {
                if enabled {
                        steps++
                }
        }
 
-       taskCtx := helper.NewDefaultTaskContext(cfg, logger, db, ctx, name, 
subtasks, progress)
+       taskCtx := helper.NewDefaultTaskContext(cfg, logger, db, ctx, name, 
subtasksFlag, progress)
        taskData, err := pluginTask.PrepareTaskData(taskCtx, options)
        if err != nil {
                return err
diff --git a/services/task.go b/services/task.go
index 176b99e1..a73fbae6 100644
--- a/services/task.go
+++ b/services/task.go
@@ -131,8 +131,14 @@ func CreateTask(newTask *models.NewTask) (*models.Task, 
error) {
        if err != nil {
                return nil, err
        }
+       s, err := json.Marshal(newTask.Subtasks)
+       if err != nil {
+               return nil, err
+       }
+
        task := models.Task{
                Plugin:      newTask.Plugin,
+               Subtasks:    s,
                Options:     b,
                Status:      models.TASK_CREATED,
                Message:     "",

Reply via email to