You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by kl...@apache.org on 2024/04/18 03:57:54 UTC
(incubator-devlake) branch main updated: feat: collect and extract jenkins jobs from multibranch pipelines (#7213)
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 6dca288d5 feat: collect and extract jenkins jobs from multibranch pipelines (#7213)
6dca288d5 is described below
commit 6dca288d5e33bb55a8b98995df97ead71b76a082
Author: Gustavo Bini <64...@users.noreply.github.com>
AuthorDate: Thu Apr 18 05:57:49 2024 +0200
feat: collect and extract jenkins jobs from multibranch pipelines (#7213)
* feat: collect and extract jenkins jobs from multibranch pipelines
* feat: mv additional properties from blueprint to prepare tasks
* chore: use CollectorStateManager
---------
Co-authored-by: Gustavo Bini <hi...@bini.dev>
---
backend/plugins/jenkins/api/remote_api.go | 27 +++--
backend/plugins/jenkins/e2e/jobs_test.go | 40 ++++++++
.../_raw_jenkins_api_builds_multibranch.csv | 16 +++
.../_raw_jenkins_api_jobs_multibranch.csv | 5 +
.../_raw_jenkins_api_stages_multibranch.csv | 66 ++++++++++++
.../raw_tables/_tool_jenkins_jobs_multibranch.csv | 5 +
.../_tool_jenkins_build_commits_multibranch.csv | 14 +++
.../_tool_jenkins_builds_multibranch.csv | 16 +++
.../_tool_jenkins_stages_multibranch.csv | 66 ++++++++++++
.../cicd_pipeline_commits_multibranch.csv | 14 +++
.../snapshot_tables/cicd_pipelines_multibranch.csv | 16 +++
.../snapshot_tables/cicd_scopes_multibranch.csv | 5 +
.../e2e/snapshot_tables/cicd_tasks_multibranch.csv | 68 +++++++++++++
backend/plugins/jenkins/impl/impl.go | 6 ++
.../plugins/jenkins/tasks/build_cicd_convertor.go | 23 ++++-
backend/plugins/jenkins/tasks/build_collector.go | 111 ++++++++++++++++++++-
.../jenkins/tasks/build_commit_convertor.go | 21 +++-
backend/plugins/jenkins/tasks/build_extractor.go | 22 +++-
.../plugins/jenkins/tasks/build_stages_enricher.go | 21 +++-
.../tasks/{build_collector.go => job_collector.go} | 63 +++++-------
.../tasks/{stage_extractor.go => job_extractor.go} | 47 ++++-----
backend/plugins/jenkins/tasks/shared.go | 6 +-
backend/plugins/jenkins/tasks/stage_collector.go | 75 ++++++++++++++
backend/plugins/jenkins/tasks/stage_convertor.go | 14 ++-
backend/plugins/jenkins/tasks/stage_extractor.go | 3 +-
backend/plugins/jenkins/tasks/task_data.go | 25 +++--
26 files changed, 688 insertions(+), 107 deletions(-)
diff --git a/backend/plugins/jenkins/api/remote_api.go b/backend/plugins/jenkins/api/remote_api.go
index 4a9b72c3f..c5052addd 100644
--- a/backend/plugins/jenkins/api/remote_api.go
+++ b/backend/plugins/jenkins/api/remote_api.go
@@ -53,16 +53,19 @@ func listJenkinsRemoteScopes(
parentId = &groupId
}
getJobsPageCallBack := func(job *models.Job) errors.Error {
- if job.Jobs != nil {
- // this is a group
- job.Path = groupId
+ switch job.Class {
+ case "org.jenkinsci.plugins.workflow.job.WorkflowJob":
+ // this is a scope
+ jenkinsJob := job.ToJenkinsJob()
children = append(children, dsmodels.DsRemoteApiScopeListEntry[models.JenkinsJob]{
- Type: api.RAS_ENTRY_TYPE_GROUP,
- Id: fmt.Sprintf("%s/job/%s", job.Path, job.Name),
- Name: job.Name,
+ Type: api.RAS_ENTRY_TYPE_SCOPE,
+ Id: jenkinsJob.ScopeId(),
+ Name: jenkinsJob.ScopeName(),
+ FullName: jenkinsJob.ScopeFullName(),
+ Data: jenkinsJob,
ParentId: parentId,
})
- } else {
+ case "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject":
// this is a scope
jenkinsJob := job.ToJenkinsJob()
children = append(children, dsmodels.DsRemoteApiScopeListEntry[models.JenkinsJob]{
@@ -73,7 +76,17 @@ func listJenkinsRemoteScopes(
Data: jenkinsJob,
ParentId: parentId,
})
+ default:
+ // this is a group
+ job.Path = groupId
+ children = append(children, dsmodels.DsRemoteApiScopeListEntry[models.JenkinsJob]{
+ Type: api.RAS_ENTRY_TYPE_GROUP,
+ Id: fmt.Sprintf("%s/job/%s", job.Path, job.Name),
+ Name: job.Name,
+ ParentId: parentId,
+ })
}
+
return nil
}
_, err = GetJobsPage(apiClient, groupId, page.Page-1, page.PerPage, getJobsPageCallBack)
diff --git a/backend/plugins/jenkins/e2e/jobs_test.go b/backend/plugins/jenkins/e2e/jobs_test.go
index 816cb377b..b4cfa524e 100644
--- a/backend/plugins/jenkins/e2e/jobs_test.go
+++ b/backend/plugins/jenkins/e2e/jobs_test.go
@@ -27,6 +27,8 @@ import (
"github.com/apache/incubator-devlake/plugins/jenkins/impl"
"github.com/apache/incubator-devlake/plugins/jenkins/models"
"github.com/apache/incubator-devlake/plugins/jenkins/tasks"
+
+ api "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
)
func TestJenkinsJobsDataFlow(t *testing.T) {
@@ -52,3 +54,41 @@ func TestJenkinsJobsDataFlow(t *testing.T) {
IgnoreTypes: []interface{}{common.NoPKModel{}},
})
}
+
+func TestJenkinsMultibranchJobsDataFlow(t *testing.T) {
+ var jenkins impl.Jenkins
+ dataflowTester := e2ehelper.NewDataFlowTester(t, "jenkins", jenkins)
+
+ taskData := &tasks.JenkinsTaskData{
+ Options: &tasks.JenkinsOptions{
+ ConnectionId: 1,
+ JobName: `devlake-jenkins`,
+ JobFullName: `github_org/devlake-jenkins`,
+ JobPath: ``,
+ Class: `org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject`,
+ ScopeConfig: new(models.JenkinsScopeConfig),
+ },
+ Connection: &models.JenkinsConnection{
+ JenkinsConn: models.JenkinsConn{
+ RestConnection: api.RestConnection{
+ Endpoint: "https://1457-62-195-68-26.ngrok-free.app",
+ },
+ },
+ },
+ }
+
+ dataflowTester.FlushTabler(&models.JenkinsJob{})
+ dataflowTester.ImportCsvIntoRawTable("./raw_tables/_raw_jenkins_api_jobs_multibranch.csv", "_raw_jenkins_api_jobs")
+ dataflowTester.Subtask(tasks.ExtractApiJobsMeta, taskData)
+ dataflowTester.VerifyTableWithOptions(&models.JenkinsJob{}, e2ehelper.TableOptions{
+ CSVRelPath: "./raw_tables/_tool_jenkins_jobs_multibranch.csv",
+ IgnoreTypes: []interface{}{common.NoPKModel{}},
+ })
+
+ dataflowTester.FlushTabler(&devops.CicdScope{})
+ dataflowTester.Subtask(tasks.ConvertJobsMeta, taskData)
+ dataflowTester.VerifyTableWithOptions(&devops.CicdScope{}, e2ehelper.TableOptions{
+ CSVRelPath: "./snapshot_tables/cicd_scopes_multibranch.csv",
+ IgnoreTypes: []interface{}{common.NoPKModel{}},
+ })
+}
diff --git a/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_builds_multibranch.csv b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_builds_multibranch.csv
new file mode 100644
index 000000000..785dd643a
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_builds_multibranch.csv
@@ -0,0 +1,16 @@
+"id","params","data","url","input","created_at"
+1,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch main\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevi [...]
+2,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch main\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevi [...]
+3,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch main\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevi [...]
+4,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchIndexingCause\",\"shortDescription\":\"Branch indexing\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevision\": [...]
+5,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Pull request #2 updated\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevisi [...]
+6,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Pull request #2 opened\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevisio [...]
+7,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-1\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuil [...]
+8,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchIndexingCause\",\"shortDescription\":\"Branch indexing\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevision\": [...]
+9,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchIndexingCause\",\"shortDescription\":\"Branch indexing\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBuiltRevision\": [...]
+10,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBui [...]
+11,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{},{\"_class\":\"org.jenkinsci.plugins.displayurlapi.action [...]
+12,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{},{\"_class\":\"org.jenkinsci.plugins.displayurlapi.action [...]
+13,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBui [...]
+14,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBui [...]
+15,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_class\":\"org.jenkinsci.plugins.workflow.job.WorkflowRun\",\"actions\":[{\"_class\":\"hudson.model.CauseAction\",\"causes\":[{\"_class\":\"jenkins.branch.BranchEventCause\",\"shortDescription\":\"Push event to branch feature-2\"}]},{\"_class\":\"jenkins.scm.api.SCMRevisionAction\"},{\"_class\":\"org.jenkinsci.plugins.workflow.libs.LibrariesAction\"},{},{},{\"_class\":\"hudson.plugins.git.util.BuildData\",\"lastBui [...]
diff --git a/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_jobs_multibranch.csv b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_jobs_multibranch.csv
new file mode 100644
index 000000000..589206016
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_jobs_multibranch.csv
@@ -0,0 +1,5 @@
+"id","params","data","url","input","created_at"
+1,"{""ConnectionId"":1,""FullName"":""github_org/devlake-jenkins""}","{""_class"":""org.jenkinsci.plugins.workflow.job.WorkflowJob"",""description"":null,""fullName"":""github_org/devlake-jenkins/feature-1"",""name"":""feature-1"",""url"":""https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/"",""color"":""blue""}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/api/json?tree=jobs%5BfullName%2Cname%2Ccla [...]
+2,"{""ConnectionId"":1,""FullName"":""github_org/devlake-jenkins""}","{""_class"":""org.jenkinsci.plugins.workflow.job.WorkflowJob"",""description"":null,""fullName"":""github_org/devlake-jenkins/feature-2"",""name"":""feature-2"",""url"":""https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/"",""color"":""aborted""}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/api/json?tree=jobs%5BfullName%2Cname%2C [...]
+3,"{""ConnectionId"":1,""FullName"":""github_org/devlake-jenkins""}","{""_class"":""org.jenkinsci.plugins.workflow.job.WorkflowJob"",""description"":null,""fullName"":""github_org/devlake-jenkins/main"",""name"":""main"",""url"":""https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/"",""color"":""blue""}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/api/json?tree=jobs%5BfullName%2Cname%2Cclass%2Curl%2Ccolo [...]
+4,"{""ConnectionId"":1,""FullName"":""github_org/devlake-jenkins""}","{""_class"":""org.jenkinsci.plugins.workflow.job.WorkflowJob"",""description"":null,""fullName"":""github_org/devlake-jenkins/PR-2"",""name"":""PR-2"",""url"":""https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/"",""color"":""blue""}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/api/json?tree=jobs%5BfullName%2Cname%2Cclass%2Curl%2Ccolo [...]
diff --git a/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_stages_multibranch.csv b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_stages_multibranch.csv
new file mode 100644
index 000000000..282c0e150
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/raw_tables/_raw_jenkins_api_stages_multibranch.csv
@@ -0,0 +1,66 @@
+"id","params","data","url","input","created_at"
+1,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/2/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277302838,\"durationMillis\":2299,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/2/wfapi/describe","{\" [...]
+2,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/2/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277305172,\"durationMillis\":5526,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/2/wfapi/describe","{\"Number\": \"2\" [...]
+3,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/2/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277310709,\"durationMillis\":10223,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/2/wfapi/describe","{\"Number\": \"2\", [...]
+4,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/2/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277320947,\"durationMillis\":12470,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/2/wfapi/describe","{\"Number\": \"2\", \ [...]
+5,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/2/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277333432,\"durationMillis\":3552,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/2/wfapi/describe","{\"Number\": \"2\", [...]
+6,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277513092,\"durationMillis\":3894,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/wfapi/describe","{\" [...]
+7,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/execution/node/15/wfapi/describe\"}},\"id\":\"15\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277517022,\"durationMillis\":2196,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.n [...]
+8,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/execution/node/20/wfapi/describe\"}},\"id\":\"20\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277519230,\"durationMillis\":18,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok- [...]
+9,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/execution/node/24/wfapi/describe\"}},\"id\":\"24\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277519255,\"durationMillis\":13,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-f [...]
+10,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/1/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277519275,\"durationMillis\":11,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngro [...]
+11,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277543070,\"durationMillis\":1836,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/wfapi/describe","{\ [...]
+12,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277544926,\"durationMillis\":5519,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/wfapi/describe","{\"Number\": \"2\ [...]
+13,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277550462,\"durationMillis\":5521,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/wfapi/describe","{\"Number\": \"2\", [...]
+14,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277555994,\"durationMillis\":12447,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/wfapi/describe","{\"Number\": \"2\", [...]
+15,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277568457,\"durationMillis\":3553,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/2/wfapi/describe","{\"Number\": \"2\", [...]
+16,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/1/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275817796,\"durationMillis\":5502,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/1/wfapi/describe","{ [...]
+17,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/1/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275823323,\"durationMillis\":5543,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/1/wfapi/describe","{\"Number\": \"1 [...]
+18,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/1/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275828881,\"durationMillis\":10233,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/1/wfapi/describe","{\"Number\": \"1\" [...]
+19,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/1/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275839129,\"durationMillis\":12445,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/1/wfapi/describe","{\"Number\": \"1\", [...]
+20,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/1/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275851583,\"durationMillis\":3549,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/1/wfapi/describe","{\"Number\": \"1\" [...]
+21,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/2/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711276327154,\"durationMillis\":2318,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/2/wfapi/describe","{ [...]
+22,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/2/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711276329502,\"durationMillis\":5545,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/2/wfapi/describe","{\"Number\": \"2 [...]
+23,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/2/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711276335061,\"durationMillis\":10232,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/2/wfapi/describe","{\"Number\": \"2\" [...]
+24,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/2/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711276345310,\"durationMillis\":12463,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/2/wfapi/describe","{\"Number\": \"2\", [...]
+25,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/2/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711276357788,\"durationMillis\":3570,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/2/wfapi/describe","{\"Number\": \"2\" [...]
+26,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/3/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277072754,\"durationMillis\":2318,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/3/wfapi/describe","{ [...]
+27,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/3/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277075100,\"durationMillis\":5546,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/3/wfapi/describe","{\"Number\": \"3 [...]
+28,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/3/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277080662,\"durationMillis\":10218,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/3/wfapi/describe","{\"Number\": \"3\" [...]
+29,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/3/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277090895,\"durationMillis\":12441,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/3/wfapi/describe","{\"Number\": \"3\", [...]
+30,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-1/3/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277103348,\"durationMillis\":3555,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/3/wfapi/describe","{\"Number\": \"3\" [...]
+31,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/1/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277142703,\"durationMillis\":2244,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/1/wfapi/describe","{ [...]
+32,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/1/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277144974,\"durationMillis\":5541,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/1/wfapi/describe","{\"Number\": \"1 [...]
+33,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/1/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277150529,\"durationMillis\":10224,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/1/wfapi/describe","{\"Number\": \"1\" [...]
+34,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/1/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277160766,\"durationMillis\":12449,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/1/wfapi/describe","{\"Number\": \"1\", [...]
+35,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/1/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277173228,\"durationMillis\":3567,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/1/wfapi/describe","{\"Number\": \"1\" [...]
+36,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/2/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277157667,\"durationMillis\":2273,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/2/wfapi/describe","{ [...]
+37,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/2/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277159966,\"durationMillis\":5534,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/2/wfapi/describe","{\"Number\": \"2 [...]
+38,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/2/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277165515,\"durationMillis\":10220,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/2/wfapi/describe","{\"Number\": \"2\" [...]
+39,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/2/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277175748,\"durationMillis\":12445,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/2/wfapi/describe","{\"Number\": \"2\", [...]
+40,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/2/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277188207,\"durationMillis\":3549,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/2/wfapi/describe","{\"Number\": \"2\" [...]
+41,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/3/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277192935,\"durationMillis\":2285,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/3/wfapi/describe","{ [...]
+42,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/3/execution/node/15/wfapi/describe\"}},\"id\":\"15\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277195262,\"durationMillis\":5526,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/3/wfapi/describe","{\"Number\": \"3 [...]
+43,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/3/execution/node/20/wfapi/describe\"}},\"id\":\"20\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277200803,\"durationMillis\":10214,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/3/wfapi/describe","{\"Number\": \"3\" [...]
+44,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/3/execution/node/25/wfapi/describe\"}},\"id\":\"25\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277211031,\"durationMillis\":12456,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/3/wfapi/describe","{\"Number\": \"3\", [...]
+45,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/feature-2/3/execution/node/30/wfapi/describe\"}},\"id\":\"30\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277223500,\"durationMillis\":3557,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/3/wfapi/describe","{\"Number\": \"3\" [...]
+46,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277457972,\"durationMillis\":2419,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/wfapi/des [...]
+47,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/execution/node/15/wfapi/describe\"}},\"id\":\"15\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277460433,\"durationMillis\":2305,\"pauseDurationMillis\":0}","https://1457-62-195-6 [...]
+48,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/execution/node/20/wfapi/describe\"}},\"id\":\"20\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277462749,\"durationMillis\":38,\"pauseDurationMillis\":0}","https://1457-62-195-68-26. [...]
+49,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/execution/node/24/wfapi/describe\"}},\"id\":\"24\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277462795,\"durationMillis\":16,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.n [...]
+50,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/feature-2/6/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"ABORTED\",\"error\":{\"message\":null,\"type\":\"org.jenkinsci.plugins.workflow.steps.FlowInterruptedException\"},\"startTimeMillis\":1711277462819,\"durationMillis\":16,\"pauseDurationMillis\":0}","https://1457-62-195-68-26 [...]
+51,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/main/1/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275817797,\"durationMillis\":2453,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/1/wfapi/describe","{\"Number\" [...]
+52,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/main/1/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275820311,\"durationMillis\":5546,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/1/wfapi/describe","{\"Number\": \"1\", \"JobP [...]
+53,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/main/1/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275825866,\"durationMillis\":10227,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/1/wfapi/describe","{\"Number\": \"1\", \"JobPat [...]
+54,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/main/1/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275836110,\"durationMillis\":12467,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/1/wfapi/describe","{\"Number\": \"1\", \"JobPath [...]
+55,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/job/github_org/job/devlake-jenkins/job/main/1/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711275848591,\"durationMillis\":3557,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/1/wfapi/describe","{\"Number\": \"1\", \"JobPat [...]
+56,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/3/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277503096,\"durationMillis\":2390,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/3/wfapi/describe","{\ [...]
+57,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/3/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277505517,\"durationMillis\":5537,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/3/wfapi/describe","{\"Number\": \"3\ [...]
+58,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/3/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277511068,\"durationMillis\":10220,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/3/wfapi/describe","{\"Number\": \"3\", [...]
+59,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/3/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277521301,\"durationMillis\":12462,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/3/wfapi/describe","{\"Number\": \"3\", [...]
+60,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/3/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277533776,\"durationMillis\":3546,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/3/wfapi/describe","{\"Number\": \"3\", [...]
+61,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/4/execution/node/6/wfapi/describe\"}},\"id\":\"6\",\"name\":\"Declarative: Checkout SCM\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277553013,\"durationMillis\":2231,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/4/wfapi/describe","{\ [...]
+62,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/4/execution/node/13/wfapi/describe\"}},\"id\":\"13\",\"name\":\"checkout\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277555275,\"durationMillis\":5511,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/4/wfapi/describe","{\"Number\": \"4\ [...]
+63,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/4/execution/node/18/wfapi/describe\"}},\"id\":\"18\",\"name\":\"build\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277560796,\"durationMillis\":5531,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/4/wfapi/describe","{\"Number\": \"4\", [...]
+64,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/4/execution/node/23/wfapi/describe\"}},\"id\":\"23\",\"name\":\"test\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277566345,\"durationMillis\":12433,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/4/wfapi/describe","{\"Number\": \"4\", [...]
+65,"{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","{\"_links\":{\"self\":{\"href\":\"/view/all/job/github_org/job/devlake-jenkins/job/main/4/execution/node/28/wfapi/describe\"}},\"id\":\"28\",\"name\":\"deploy\",\"execNode\":\"\",\"status\":\"SUCCESS\",\"startTimeMillis\":1711277578791,\"durationMillis\":3551,\"pauseDurationMillis\":0}","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/4/wfapi/describe","{\"Number\": \"4\", [...]
diff --git a/backend/plugins/jenkins/e2e/raw_tables/_tool_jenkins_jobs_multibranch.csv b/backend/plugins/jenkins/e2e/raw_tables/_tool_jenkins_jobs_multibranch.csv
new file mode 100644
index 000000000..9fb58be87
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/raw_tables/_tool_jenkins_jobs_multibranch.csv
@@ -0,0 +1,5 @@
+connection_id,full_name,name,path,class,color,base,url,description,primary_view,created_at,updated_at,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark,scope_config_id
+1,"github_org/devlake-jenkins/PR-2","PR-2","/view/all/job/github_org/job/devlake-jenkins/job/PR-2/","org.jenkinsci.plugins.workflow.job.WorkflowJob","blue",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/org.jenkinsci.plugins.workflow.job.WorkflowJob","2024-03-24 11:01:19.321","2024-03-24 11:01:19.321","{""ConnectionId"":1,""FullName"":""github [...]
+1,"github_org/devlake-jenkins/feature-1","feature-1","/view/all/job/github_org/job/devlake-jenkins/job/feature-1/","org.jenkinsci.plugins.workflow.job.WorkflowJob","blue",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/org.jenkinsci.plugins.workflow.job.WorkflowJob","2024-03-24 11:01:19.321","2024-03-24 11:01:19.321","{""ConnectionId" [...]
+1,"github_org/devlake-jenkins/feature-2","feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/","org.jenkinsci.plugins.workflow.job.WorkflowJob","aborted",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/org.jenkinsci.plugins.workflow.job.WorkflowJob","2024-03-24 11:01:19.321","2024-03-24 11:01:19.321","{""Connection [...]
+1,"github_org/devlake-jenkins/main","main","/view/all/job/github_org/job/devlake-jenkins/job/main/","org.jenkinsci.plugins.workflow.job.WorkflowJob","blue",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/",,"https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/org.jenkinsci.plugins.workflow.job.WorkflowJob","2024-03-24 11:01:19.321","2024-03-24 11:01:19.321","{""ConnectionId"":1,""FullName"":""github [...]
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_build_commits_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_build_commits_multibranch.csv
new file mode 100644
index 000000000..93fad1886
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_build_commits_multibranch.csv
@@ -0,0 +1,14 @@
+connection_id,build_name,commit_sha,branch,repo_url,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+1,"github_org/devlake-jenkins/PR-2#1","aba54481a73573c0587f26fbd4c9788eb2bf2398","PR-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",6,""
+1,"github_org/devlake-jenkins/PR-2#2","49359d217ea617c7e4771235979b56015172ba6c","PR-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",5,""
+1,"github_org/devlake-jenkins/feature-1#1","87f0f9ee7c305c561c96f66ed8c71c85df4b940f","feature-1","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",9,""
+1,"github_org/devlake-jenkins/feature-1#2","eae3667426e1da0d8cab523e372e6771a39b16a7","feature-1","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",8,""
+1,"github_org/devlake-jenkins/feature-1#3","3ff14f4a781018e6e800ded3a5ac95fa2f9bb26f","feature-1","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",7,""
+1,"github_org/devlake-jenkins/feature-2#1","2578423ba5c348fb9948279f3ea64ed650fecd8a","feature-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",15,""
+1,"github_org/devlake-jenkins/feature-2#2","2578423ba5c348fb9948279f3ea64ed650fecd8a","feature-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",14,""
+1,"github_org/devlake-jenkins/feature-2#3","881b398774e020772bca7fdd7fdc60e7250f53ef","feature-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",13,""
+1,"github_org/devlake-jenkins/feature-2#6","aba54481a73573c0587f26fbd4c9788eb2bf2398","feature-2","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",10,""
+1,"github_org/devlake-jenkins/main#1","87f0f9ee7c305c561c96f66ed8c71c85df4b940f","main","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",4,""
+1,"github_org/devlake-jenkins/main#2","f521ff9c806e74b9100c8fc87d07ac504f828f93","main","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",3,""
+1,"github_org/devlake-jenkins/main#3","78b8e3a2029f991982039e4ed6d7b1f9c6670497","main","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",2,""
+1,"github_org/devlake-jenkins/main#4","c83ae02076382670e286ac2474b7a7327fc28cde","main","git@github.com:gustavobini/devlake-jenkins.git","2024-03-24 11:01:20.776","2024-03-24 11:01:20.776","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",1,""
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_builds_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_builds_multibranch.csv
new file mode 100644
index 000000000..14f386a31
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_builds_multibranch.csv
@@ -0,0 +1,16 @@
+connection_id,full_name,job_name,job_path,duration,estimated_duration,number,result,timestamp,start_time,has_stages,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.210","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",6,"",1,"PR-2","/view/all/job/github_org/job/devlake-jenkins/job/PR-2/",7390,"github_org/devlake-jenkins/PR-2#1",30086,1,"ABORTED",1711277511931,"2024-03-24 10:51:51.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.211","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",5,"",1,"PR-2","/view/all/job/github_org/job/devlake-jenkins/job/PR-2/",30086,"github_org/devlake-jenkins/PR-2#2",30086,2,"SUCCESS",1711277541959,"2024-03-24 10:52:21.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.211","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",9,"",1,"feature-1","/view/all/job/github_org/job/devlake-jenkins/job/feature-1/",39545,"github_org/devlake-jenkins/feature-1#1",36750,1,"SUCCESS",1711275815628,"2024-03-24 10:23:35.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.212","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",8,"",1,"feature-1","/view/all/job/github_org/job/devlake-jenkins/job/feature-1/",35351,"github_org/devlake-jenkins/feature-1#2",36750,2,"SUCCESS",1711276326044,"2024-03-24 10:32:06.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.212","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",7,"",1,"feature-1","/view/all/job/github_org/job/devlake-jenkins/job/feature-1/",35354,"github_org/devlake-jenkins/feature-1#3",36750,3,"SUCCESS",1711277071589,"2024-03-24 10:44:31.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.212","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",15,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",35206,"github_org/devlake-jenkins/feature-2#1",35268,1,"SUCCESS",1711277141627,"2024-03-24 10:45:41.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.213","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",14,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",35162,"github_org/devlake-jenkins/feature-2#2",35268,2,"SUCCESS",1711277156634,"2024-03-24 10:45:56.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.213","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",13,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",35435,"github_org/devlake-jenkins/feature-2#3",35268,3,"SUCCESS",1711277191663,"2024-03-24 10:46:31.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:20.778","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",12,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",976,"github_org/devlake-jenkins/feature-2#4",35268,4,"FAILURE",1711277261723,"2024-03-24 10:47:41.000","","WorkflowRun","",0,0
+"2024-03-24 11:01:20.778","2024-03-24 11:01:20.778","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",11,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",1098,"github_org/devlake-jenkins/feature-2#5",35268,5,"FAILURE",1711277371815,"2024-03-24 10:49:31.000","","WorkflowRun","",0,0
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.214","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",10,"",1,"feature-2","/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",5993,"github_org/devlake-jenkins/feature-2#6",35268,6,"ABORTED",1711277456887,"2024-03-24 10:50:56.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.214","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",4,"",1,"main","/view/all/job/github_org/job/devlake-jenkins/job/main/",36568,"github_org/devlake-jenkins/main#1",33703,1,"SUCCESS",1711275815622,"2024-03-24 10:23:35.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.215","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",3,"",1,"main","/view/all/job/github_org/job/devlake-jenkins/job/main/",35260,"github_org/devlake-jenkins/main#2",33703,2,"SUCCESS",1711277301765,"2024-03-24 10:48:21.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.215","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",2,"",1,"main","/view/all/job/github_org/job/devlake-jenkins/job/main/",35435,"github_org/devlake-jenkins/main#3",33703,3,"SUCCESS",1711277501923,"2024-03-24 10:51:41.000","","WorkflowRun","",0,1
+"2024-03-24 11:01:20.778","2024-03-24 11:01:26.215","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",1,"",1,"main","/view/all/job/github_org/job/devlake-jenkins/job/main/",30415,"github_org/devlake-jenkins/main#4",33703,4,"SUCCESS",1711277551963,"2024-03-24 10:52:31.000","","WorkflowRun","",0,1
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_stages_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_stages_multibranch.csv
new file mode 100644
index 000000000..0841a6203
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/_tool_jenkins_stages_multibranch.csv
@@ -0,0 +1,66 @@
+connection_id,id,build_name,name,exec_node,status,start_time_millis,duration_millis,pause_duration_millis,type,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",12,"",1,"13","checkout","","SUCCESS",1711277544926,5519,0,"github_org/devlake-jenkins/PR-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",17,"",1,"13","checkout","","SUCCESS",1711275823323,5543,0,"github_org/devlake-jenkins/feature-1#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",22,"",1,"13","checkout","","SUCCESS",1711276329502,5545,0,"github_org/devlake-jenkins/feature-1#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",27,"",1,"13","checkout","","SUCCESS",1711277075100,5546,0,"github_org/devlake-jenkins/feature-1#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",32,"",1,"13","checkout","","SUCCESS",1711277144974,5541,0,"github_org/devlake-jenkins/feature-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",37,"",1,"13","checkout","","SUCCESS",1711277159966,5534,0,"github_org/devlake-jenkins/feature-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",52,"",1,"13","checkout","","SUCCESS",1711275820311,5546,0,"github_org/devlake-jenkins/main#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",2,"",1,"13","checkout","","SUCCESS",1711277305172,5526,0,"github_org/devlake-jenkins/main#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",57,"",1,"13","checkout","","SUCCESS",1711277505517,5537,0,"github_org/devlake-jenkins/main#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",62,"",1,"13","checkout","","SUCCESS",1711277555275,5511,0,"github_org/devlake-jenkins/main#4",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",7,"",1,"15","checkout","","ABORTED",1711277517022,2196,0,"github_org/devlake-jenkins/PR-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",42,"",1,"15","checkout","","SUCCESS",1711277195262,5526,0,"github_org/devlake-jenkins/feature-2#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",47,"",1,"15","checkout","","ABORTED",1711277460433,2305,0,"github_org/devlake-jenkins/feature-2#6",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",13,"",1,"18","build","","SUCCESS",1711277550462,5521,0,"github_org/devlake-jenkins/PR-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",18,"",1,"18","build","","SUCCESS",1711275828881,10233,0,"github_org/devlake-jenkins/feature-1#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",23,"",1,"18","build","","SUCCESS",1711276335061,10232,0,"github_org/devlake-jenkins/feature-1#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",28,"",1,"18","build","","SUCCESS",1711277080662,10218,0,"github_org/devlake-jenkins/feature-1#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",33,"",1,"18","build","","SUCCESS",1711277150529,10224,0,"github_org/devlake-jenkins/feature-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",38,"",1,"18","build","","SUCCESS",1711277165515,10220,0,"github_org/devlake-jenkins/feature-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",53,"",1,"18","build","","SUCCESS",1711275825866,10227,0,"github_org/devlake-jenkins/main#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",3,"",1,"18","build","","SUCCESS",1711277310709,10223,0,"github_org/devlake-jenkins/main#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",58,"",1,"18","build","","SUCCESS",1711277511068,10220,0,"github_org/devlake-jenkins/main#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",63,"",1,"18","build","","SUCCESS",1711277560796,5531,0,"github_org/devlake-jenkins/main#4",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",8,"",1,"20","build","","ABORTED",1711277519230,18,0,"github_org/devlake-jenkins/PR-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",43,"",1,"20","build","","SUCCESS",1711277200803,10214,0,"github_org/devlake-jenkins/feature-2#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",48,"",1,"20","build","","ABORTED",1711277462749,38,0,"github_org/devlake-jenkins/feature-2#6",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",14,"",1,"23","test","","SUCCESS",1711277555994,12447,0,"github_org/devlake-jenkins/PR-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",19,"",1,"23","test","","SUCCESS",1711275839129,12445,0,"github_org/devlake-jenkins/feature-1#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",24,"",1,"23","test","","SUCCESS",1711276345310,12463,0,"github_org/devlake-jenkins/feature-1#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",29,"",1,"23","test","","SUCCESS",1711277090895,12441,0,"github_org/devlake-jenkins/feature-1#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",34,"",1,"23","test","","SUCCESS",1711277160766,12449,0,"github_org/devlake-jenkins/feature-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",39,"",1,"23","test","","SUCCESS",1711277175748,12445,0,"github_org/devlake-jenkins/feature-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",54,"",1,"23","test","","SUCCESS",1711275836110,12467,0,"github_org/devlake-jenkins/main#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",4,"",1,"23","test","","SUCCESS",1711277320947,12470,0,"github_org/devlake-jenkins/main#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",59,"",1,"23","test","","SUCCESS",1711277521301,12462,0,"github_org/devlake-jenkins/main#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",64,"",1,"23","test","","SUCCESS",1711277566345,12433,0,"github_org/devlake-jenkins/main#4",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",9,"",1,"24","test","","ABORTED",1711277519255,13,0,"github_org/devlake-jenkins/PR-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",49,"",1,"24","test","","ABORTED",1711277462795,16,0,"github_org/devlake-jenkins/feature-2#6",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",44,"",1,"25","test","","SUCCESS",1711277211031,12456,0,"github_org/devlake-jenkins/feature-2#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",10,"",1,"28","deploy","","ABORTED",1711277519275,11,0,"github_org/devlake-jenkins/PR-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",15,"",1,"28","deploy","","SUCCESS",1711277568457,3553,0,"github_org/devlake-jenkins/PR-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",20,"",1,"28","deploy","","SUCCESS",1711275851583,3549,0,"github_org/devlake-jenkins/feature-1#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",25,"",1,"28","deploy","","SUCCESS",1711276357788,3570,0,"github_org/devlake-jenkins/feature-1#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",30,"",1,"28","deploy","","SUCCESS",1711277103348,3555,0,"github_org/devlake-jenkins/feature-1#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",35,"",1,"28","deploy","","SUCCESS",1711277173228,3567,0,"github_org/devlake-jenkins/feature-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",40,"",1,"28","deploy","","SUCCESS",1711277188207,3549,0,"github_org/devlake-jenkins/feature-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",50,"",1,"28","deploy","","ABORTED",1711277462819,16,0,"github_org/devlake-jenkins/feature-2#6",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",55,"",1,"28","deploy","","SUCCESS",1711275848591,3557,0,"github_org/devlake-jenkins/main#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",5,"",1,"28","deploy","","SUCCESS",1711277333432,3552,0,"github_org/devlake-jenkins/main#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",60,"",1,"28","deploy","","SUCCESS",1711277533776,3546,0,"github_org/devlake-jenkins/main#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",65,"",1,"28","deploy","","SUCCESS",1711277578791,3551,0,"github_org/devlake-jenkins/main#4",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",45,"",1,"30","deploy","","SUCCESS",1711277223500,3557,0,"github_org/devlake-jenkins/feature-2#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",6,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277513092,3894,0,"github_org/devlake-jenkins/PR-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",11,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277543070,1836,0,"github_org/devlake-jenkins/PR-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",16,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711275817796,5502,0,"github_org/devlake-jenkins/feature-1#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",21,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711276327154,2318,0,"github_org/devlake-jenkins/feature-1#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",26,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277072754,2318,0,"github_org/devlake-jenkins/feature-1#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",31,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277142703,2244,0,"github_org/devlake-jenkins/feature-2#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",36,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277157667,2273,0,"github_org/devlake-jenkins/feature-2#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",41,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277192935,2285,0,"github_org/devlake-jenkins/feature-2#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",46,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277457972,2419,0,"github_org/devlake-jenkins/feature-2#6",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",51,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711275817797,2453,0,"github_org/devlake-jenkins/main#1",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",1,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277302838,2299,0,"github_org/devlake-jenkins/main#2",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",56,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277503096,2390,0,"github_org/devlake-jenkins/main#3",""
+"2024-03-24 11:01:26.165","2024-03-24 11:01:26.165","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",61,"",1,"6","Declarative: Checkout SCM","","SUCCESS",1711277553013,2231,0,"github_org/devlake-jenkins/main#4",""
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipeline_commits_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipeline_commits_multibranch.csv
new file mode 100644
index 000000000..8210ba282
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipeline_commits_multibranch.csv
@@ -0,0 +1,14 @@
+pipeline_id,commit_sha,repo_id,repo_url,branch,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",6,"","aba54481a73573c0587f26fbd4c9788eb2bf2398","PR-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",5,"","49359d217ea617c7e4771235979b56015172ba6c","PR-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",9,"","87f0f9ee7c305c561c96f66ed8c71c85df4b940f","feature-1","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",8,"","eae3667426e1da0d8cab523e372e6771a39b16a7","feature-1","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",7,"","3ff14f4a781018e6e800ded3a5ac95fa2f9bb26f","feature-1","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",15,"","2578423ba5c348fb9948279f3ea64ed650fecd8a","feature-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",14,"","2578423ba5c348fb9948279f3ea64ed650fecd8a","feature-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",13,"","881b398774e020772bca7fdd7fdc60e7250f53ef","feature-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",10,"","aba54481a73573c0587f26fbd4c9788eb2bf2398","feature-2","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",4,"","87f0f9ee7c305c561c96f66ed8c71c85df4b940f","main","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",3,"","f521ff9c806e74b9100c8fc87d07ac504f828f93","main","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",2,"","78b8e3a2029f991982039e4ed6d7b1f9c6670497","main","git@github.com:gustavobini/devlake-jenkins.git","",""
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","2024-03-24 11:01:26.227","2024-03-24 11:01:26.227","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",1,"","c83ae02076382670e286ac2474b7a7327fc28cde","main","git@github.com:gustavobini/devlake-jenkins.git","",""
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipelines_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipelines_multibranch.csv
new file mode 100644
index 000000000..8b6fc954f
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_pipelines_multibranch.csv
@@ -0,0 +1,16 @@
+id,name,result,status,original_result,original_status,type,duration_sec,environment,created_date,finished_date,cicd_scope_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",6,"","FAILURE","ABORTED","DONE","false","","2024-03-24 10:51:51.000",\N,\N,"2024-03-24 10:51:51.000","2024-03-24 10:51:58.390",7.39,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/PR-2#1"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",5,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:52:21.000",\N,\N,"2024-03-24 10:52:21.000","2024-03-24 10:52:51.086",30.086,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/PR-2#2"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",9,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:23:35.000",\N,\N,"2024-03-24 10:23:35.000","2024-03-24 10:24:14.545",39.545,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-1#1"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",8,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:32:06.000",\N,\N,"2024-03-24 10:32:06.000","2024-03-24 10:32:41.351",35.351,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-1#2"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",7,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:44:31.000",\N,\N,"2024-03-24 10:44:31.000","2024-03-24 10:45:06.354",35.354,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-1#3"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",15,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:45:41.000",\N,\N,"2024-03-24 10:45:41.000","2024-03-24 10:46:16.206",35.206,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#1"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",14,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:45:56.000",\N,\N,"2024-03-24 10:45:56.000","2024-03-24 10:46:31.162",35.162,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#2"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",13,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:46:31.000",\N,\N,"2024-03-24 10:46:31.000","2024-03-24 10:47:06.435",35.435,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#3"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#4","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",12,"","FAILURE","FAILURE","DONE","false","","2024-03-24 10:47:41.000",\N,\N,"2024-03-24 10:47:41.000","2024-03-24 10:47:41.976",0.976,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#4"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#5","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",11,"","FAILURE","FAILURE","DONE","false","","2024-03-24 10:49:31.000",\N,\N,"2024-03-24 10:49:31.000","2024-03-24 10:49:32.098",1.098,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#5"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",10,"","FAILURE","ABORTED","DONE","false","","2024-03-24 10:50:56.000",\N,\N,"2024-03-24 10:50:56.000","2024-03-24 10:51:01.993",5.993,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/feature-2#6"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",4,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:23:35.000",\N,\N,"2024-03-24 10:23:35.000","2024-03-24 10:24:11.568",36.568,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/main#1"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",3,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:48:21.000",\N,\N,"2024-03-24 10:48:21.000","2024-03-24 10:48:56.260",35.26,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/main#2"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",2,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:51:41.000",\N,\N,"2024-03-24 10:51:41.000","2024-03-24 10:52:16.435",35.435,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/main#3"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","2024-03-24 11:01:26.218","2024-03-24 11:01:26.218","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",1,"","SUCCESS","SUCCESS","DONE","false","","2024-03-24 10:52:31.000",\N,\N,"2024-03-24 10:52:31.000","2024-03-24 10:53:01.415",30.415,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins","github_org/devlake-jenkins/main#4"
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/cicd_scopes_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_scopes_multibranch.csv
new file mode 100644
index 000000000..056c87e9d
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_scopes_multibranch.csv
@@ -0,0 +1,5 @@
+id,name,description,url,created_date,updated_date
+"jenkins:JenkinsJob:1:github_org/devlake-jenkins/PR-2","github_org/devlake-jenkins/PR-2","","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/PR-2/",,
+"jenkins:JenkinsJob:1:github_org/devlake-jenkins/feature-1","github_org/devlake-jenkins/feature-1","","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-1/",,
+"jenkins:JenkinsJob:1:github_org/devlake-jenkins/feature-2","github_org/devlake-jenkins/feature-2","","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/feature-2/",,
+"jenkins:JenkinsJob:1:github_org/devlake-jenkins/main","github_org/devlake-jenkins/main","","https://1457-62-195-68-26.ngrok-free.app/view/all/job/github_org/job/devlake-jenkins/job/main/",,
diff --git a/backend/plugins/jenkins/e2e/snapshot_tables/cicd_tasks_multibranch.csv b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_tasks_multibranch.csv
new file mode 100644
index 000000000..998fd1ebb
--- /dev/null
+++ b/backend/plugins/jenkins/e2e/snapshot_tables/cicd_tasks_multibranch.csv
@@ -0,0 +1,68 @@
+id,name,pipeline_id,result,status,original_result,original_status,type,environment,duration_sec,started_date,finished_date,cicd_scope_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#4","2024-03-24 11:01:26.219","2024-03-24 11:01:26.219","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",12,"","github_org/devlake-jenkins","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#4","FAILURE","FAILURE","DONE","false","","2024-03-24 10:47:41.000",\N,\N,"2024-03-24 10:47:41.000","2024-03-24 10:47:41.976",0.976,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#5","2024-03-24 11:01:26.219","2024-03-24 11:01:26.219","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_builds",11,"","github_org/devlake-jenkins","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#5","FAILURE","FAILURE","DONE","false","","2024-03-24 10:49:31.000",\N,\N,"2024-03-24 10:49:31.000","2024-03-24 10:49:32.098",1.098,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#1:15","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",7,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:57.000",\N,\N,"2024-03-24 10:51:57.000","2024-03-24 10:51:59.218",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#1:20","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",8,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:59.000",\N,\N,"2024-03-24 10:51:59.000","2024-03-24 10:51:59.248",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#1:24","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",9,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:59.000",\N,\N,"2024-03-24 10:51:59.000","2024-03-24 10:51:59.268",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#1:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",10,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:59.000",\N,\N,"2024-03-24 10:51:59.000","2024-03-24 10:51:59.286",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#1:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",6,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#1","FAILURE","ABORTED","DONE","SUCCESS","","2024-03-24 10:51:53.000",\N,\N,"2024-03-24 10:51:53.000","2024-03-24 10:51:56.986",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#2:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",12,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:24.000",\N,\N,"2024-03-24 10:52:24.000","2024-03-24 10:52:30.445",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#2:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",13,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:30.000",\N,\N,"2024-03-24 10:52:30.000","2024-03-24 10:52:35.983",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#2:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",14,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:35.000",\N,\N,"2024-03-24 10:52:35.000","2024-03-24 10:52:48.441",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#2:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",15,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:48.000",\N,\N,"2024-03-24 10:52:48.000","2024-03-24 10:52:52.010",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/PR-2#2:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",11,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/PR-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:23.000",\N,\N,"2024-03-24 10:52:23.000","2024-03-24 10:52:24.906",1,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#1:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",17,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:43.000",\N,\N,"2024-03-24 10:23:43.000","2024-03-24 10:23:48.866",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#1:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",18,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:48.000",\N,\N,"2024-03-24 10:23:48.000","2024-03-24 10:23:59.114",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#1:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",19,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:59.000",\N,\N,"2024-03-24 10:23:59.000","2024-03-24 10:24:11.574",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#1:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",20,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:24:11.000",\N,\N,"2024-03-24 10:24:11.000","2024-03-24 10:24:15.132",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#1:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",16,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:37.000",\N,\N,"2024-03-24 10:23:37.000","2024-03-24 10:23:43.298",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#2:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",22,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:32:09.000",\N,\N,"2024-03-24 10:32:09.000","2024-03-24 10:32:15.047",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#2:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",23,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:32:15.000",\N,\N,"2024-03-24 10:32:15.000","2024-03-24 10:32:25.293",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#2:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",24,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:32:25.000",\N,\N,"2024-03-24 10:32:25.000","2024-03-24 10:32:37.773",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#2:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",25,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:32:37.000",\N,\N,"2024-03-24 10:32:37.000","2024-03-24 10:32:41.358",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#2:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",21,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:32:07.000",\N,\N,"2024-03-24 10:32:07.000","2024-03-24 10:32:09.472",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#3:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",27,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:44:35.000",\N,\N,"2024-03-24 10:44:35.000","2024-03-24 10:44:40.646",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#3:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",28,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:44:40.000",\N,\N,"2024-03-24 10:44:40.000","2024-03-24 10:44:50.880",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#3:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",29,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:44:50.000",\N,\N,"2024-03-24 10:44:50.000","2024-03-24 10:45:03.336",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#3:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",30,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:03.000",\N,\N,"2024-03-24 10:45:03.000","2024-03-24 10:45:06.903",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-1#3:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",26,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-1#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:44:32.000",\N,\N,"2024-03-24 10:44:32.000","2024-03-24 10:44:35.072",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#1:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",32,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:44.000",\N,\N,"2024-03-24 10:45:44.000","2024-03-24 10:45:50.515",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#1:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",33,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:50.000",\N,\N,"2024-03-24 10:45:50.000","2024-03-24 10:46:00.753",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#1:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",34,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:00.000",\N,\N,"2024-03-24 10:46:00.000","2024-03-24 10:46:13.215",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#1:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",35,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:13.000",\N,\N,"2024-03-24 10:46:13.000","2024-03-24 10:46:16.795",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#1:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",31,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:42.000",\N,\N,"2024-03-24 10:45:42.000","2024-03-24 10:45:44.947",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#2:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",37,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:59.000",\N,\N,"2024-03-24 10:45:59.000","2024-03-24 10:46:05.500",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#2:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",38,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:05.000",\N,\N,"2024-03-24 10:46:05.000","2024-03-24 10:46:15.735",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#2:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",39,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:15.000",\N,\N,"2024-03-24 10:46:15.000","2024-03-24 10:46:28.193",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#2:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",40,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:28.000",\N,\N,"2024-03-24 10:46:28.000","2024-03-24 10:46:31.756",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#2:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",36,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:45:57.000",\N,\N,"2024-03-24 10:45:57.000","2024-03-24 10:45:59.940",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#3:15","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",42,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:35.000",\N,\N,"2024-03-24 10:46:35.000","2024-03-24 10:46:40.788",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#3:20","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",43,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:40.000",\N,\N,"2024-03-24 10:46:40.000","2024-03-24 10:46:51.017",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#3:25","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",44,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:51.000",\N,\N,"2024-03-24 10:46:51.000","2024-03-24 10:47:03.487",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#3:30","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",45,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:47:03.000",\N,\N,"2024-03-24 10:47:03.000","2024-03-24 10:47:07.057",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#3:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",41,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:46:32.000",\N,\N,"2024-03-24 10:46:32.000","2024-03-24 10:46:35.220",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#6:15","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",47,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:00.000",\N,\N,"2024-03-24 10:51:00.000","2024-03-24 10:51:02.738",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#6:20","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",48,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:02.000",\N,\N,"2024-03-24 10:51:02.000","2024-03-24 10:51:02.787",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#6:24","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",49,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:02.000",\N,\N,"2024-03-24 10:51:02.000","2024-03-24 10:51:02.811",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#6:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",50,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","FAILURE","ABORTED","OTHER","ABORTED","","2024-03-24 10:51:02.000",\N,\N,"2024-03-24 10:51:02.000","2024-03-24 10:51:02.835",0,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/feature-2#6:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",46,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/feature-2#6","FAILURE","ABORTED","DONE","SUCCESS","","2024-03-24 10:50:57.000",\N,\N,"2024-03-24 10:50:57.000","2024-03-24 10:51:00.391",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#1:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",52,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:40.000",\N,\N,"2024-03-24 10:23:40.000","2024-03-24 10:23:45.857",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#1:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",53,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:45.000",\N,\N,"2024-03-24 10:23:45.000","2024-03-24 10:23:56.093",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#1:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",54,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:56.000",\N,\N,"2024-03-24 10:23:56.000","2024-03-24 10:24:08.577",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#1:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",55,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:24:08.000",\N,\N,"2024-03-24 10:24:08.000","2024-03-24 10:24:12.148",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#1:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",51,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#1","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:23:37.000",\N,\N,"2024-03-24 10:23:37.000","2024-03-24 10:23:40.250",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#2:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",2,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:48:25.000",\N,\N,"2024-03-24 10:48:25.000","2024-03-24 10:48:30.698",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#2:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",3,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:48:30.000",\N,\N,"2024-03-24 10:48:30.000","2024-03-24 10:48:40.932",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#2:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",4,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:48:40.000",\N,\N,"2024-03-24 10:48:40.000","2024-03-24 10:48:53.417",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#2:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",5,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:48:53.000",\N,\N,"2024-03-24 10:48:53.000","2024-03-24 10:48:56.984",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#2:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",1,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#2","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:48:22.000",\N,\N,"2024-03-24 10:48:22.000","2024-03-24 10:48:25.137",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#3:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",57,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:51:45.000",\N,\N,"2024-03-24 10:51:45.000","2024-03-24 10:51:51.054",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#3:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",58,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:51:51.000",\N,\N,"2024-03-24 10:51:51.000","2024-03-24 10:52:01.288",10,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#3:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",59,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:01.000",\N,\N,"2024-03-24 10:52:01.000","2024-03-24 10:52:13.763",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#3:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",60,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:13.000",\N,\N,"2024-03-24 10:52:13.000","2024-03-24 10:52:17.322",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#3:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",56,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#3","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:51:43.000",\N,\N,"2024-03-24 10:51:43.000","2024-03-24 10:51:45.486",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#4:13","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",62,"","checkout","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:35.000",\N,\N,"2024-03-24 10:52:35.000","2024-03-24 10:52:40.786",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#4:18","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",63,"","build","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:40.000",\N,\N,"2024-03-24 10:52:40.000","2024-03-24 10:52:46.327",5,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#4:23","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",64,"","test","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:46.000",\N,\N,"2024-03-24 10:52:46.000","2024-03-24 10:52:58.778",12,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#4:28","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",65,"","deploy","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:58.000",\N,\N,"2024-03-24 10:52:58.000","2024-03-24 10:53:02.342",3,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
+"jenkins:JenkinsStage:1:github_org/devlake-jenkins/main#4:6","2024-03-24 11:01:26.222","2024-03-24 11:01:26.222","{\"ConnectionId\":1,\"FullName\":\"github_org/devlake-jenkins\"}","_raw_jenkins_api_stages",61,"","Declarative: Checkout SCM","jenkins:JenkinsBuild:1:github_org/devlake-jenkins/main#4","SUCCESS","SUCCESS","DONE","SUCCESS","","2024-03-24 10:52:33.000",\N,\N,"2024-03-24 10:52:33.000","2024-03-24 10:52:35.244",2,"PRODUCTION","jenkins:JenkinsJob:1:github_org/devlake-jenkins"
diff --git a/backend/plugins/jenkins/impl/impl.go b/backend/plugins/jenkins/impl/impl.go
index 586074358..c575623fb 100644
--- a/backend/plugins/jenkins/impl/impl.go
+++ b/backend/plugins/jenkins/impl/impl.go
@@ -90,6 +90,8 @@ func (p Jenkins) Name() string {
func (p Jenkins) SubTaskMetas() []plugin.SubTaskMeta {
return []plugin.SubTaskMeta{
+ tasks.CollectApiJobsMeta,
+ tasks.ExtractApiJobsMeta,
tasks.ConvertJobsMeta,
tasks.CollectApiBuildsMeta,
tasks.ExtractApiBuildsMeta,
@@ -129,6 +131,8 @@ func (p Jenkins) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]
return nil, err
}
+ op.ConnectionEndpoint = connection.Endpoint
+
err = EnrichOptions(taskCtx, op, apiClient)
if err != nil {
return nil, err
@@ -253,6 +257,8 @@ func EnrichOptions(taskCtx plugin.TaskContext,
err = api.GetJob(apiClient, op.JobPath, op.JobName, op.JobFullName, 100, func(job *models.Job, isPath bool) errors.Error {
log.Debug(fmt.Sprintf("Current job: %s", job.FullName))
op.JobPath = job.Path
+ op.URL = job.URL
+ op.Class = job.Class
jenkinsJob := job.ToJenkinsJob()
jenkinsJob.ConnectionId = op.ConnectionId
diff --git a/backend/plugins/jenkins/tasks/build_cicd_convertor.go b/backend/plugins/jenkins/tasks/build_cicd_convertor.go
index 1ffddfc1c..22e12bd48 100644
--- a/backend/plugins/jenkins/tasks/build_cicd_convertor.go
+++ b/backend/plugins/jenkins/tasks/build_cicd_convertor.go
@@ -18,10 +18,12 @@ limitations under the License.
package tasks
import (
- "github.com/spf13/cast"
+ "fmt"
"reflect"
"time"
+ "github.com/spf13/cast"
+
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/models/domainlayer"
@@ -43,13 +45,24 @@ var ConvertBuildsToCicdTasksMeta = plugin.SubTaskMeta{
func ConvertBuildsToCicdTasks(taskCtx plugin.SubTaskContext) (err errors.Error) {
db := taskCtx.GetDal()
data := taskCtx.GetData().(*JenkinsTaskData)
+
clauses := []dal.Clause{
dal.From("_tool_jenkins_builds"),
- dal.Where(`_tool_jenkins_builds.connection_id = ?
- and _tool_jenkins_builds.job_path = ?
- and _tool_jenkins_builds.job_name = ?`,
- data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName),
}
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ clauses = append(clauses,
+ dal.Where(`_tool_jenkins_builds.connection_id = ?
+ and _tool_jenkins_builds.full_name like ?`,
+ data.Options.ConnectionId, fmt.Sprintf("%s%%", data.Options.JobFullName)))
+ } else {
+ clauses = append(clauses,
+ dal.Where(`_tool_jenkins_builds.connection_id = ?
+ and _tool_jenkins_builds.job_path = ?
+ and _tool_jenkins_builds.job_name = ?`,
+ data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName))
+ }
+
cursor, err := db.Cursor(clauses...)
if err != nil {
return err
diff --git a/backend/plugins/jenkins/tasks/build_collector.go b/backend/plugins/jenkins/tasks/build_collector.go
index 5697c2775..0d792c614 100644
--- a/backend/plugins/jenkins/tasks/build_collector.go
+++ b/backend/plugins/jenkins/tasks/build_collector.go
@@ -22,10 +22,13 @@ import (
"fmt"
"net/http"
"net/url"
+ "reflect"
"time"
+ "github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
+
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
)
@@ -40,8 +43,11 @@ var CollectApiBuildsMeta = plugin.SubTaskMeta{
}
type SimpleJob struct {
- Name string
- Path string
+ FullName string
+ Name string
+ Path string
+ Class string
+ URL string
}
type SimpleJenkinsApiBuild struct {
@@ -50,6 +56,21 @@ type SimpleJenkinsApiBuild struct {
}
func CollectApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
+ data := taskCtx.GetData().(*JenkinsTaskData)
+ logger := taskCtx.GetLogger()
+
+ logger.Debug("Collecting builds data from jenkins api, class: %s", data.Options.Class)
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ return collectMultiBranchJobApiBuilds(taskCtx)
+ }
+
+ return collectSingleJobApiBuilds(taskCtx)
+}
+
+// collectSingleJobApiBuilds collects builds data from a single job using Jenkins api.
+func collectSingleJobApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
+ // The API input is defined in the plugin's task definition, be that the UI or advanced blueprint.
data := taskCtx.GetData().(*JenkinsTaskData)
collector, err := helper.NewStatefulApiCollectorForFinalizableEntity(helper.FinalizableApiCollectorArgs{
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
@@ -117,3 +138,89 @@ func CollectApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
return collector.Execute()
}
+
+// collectMultiBranchJobApiBuilds collects builds data from a multi-branch workflow using Jenkins api.
+func collectMultiBranchJobApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
+ db := taskCtx.GetDal()
+ data := taskCtx.GetData().(*JenkinsTaskData)
+ logger := taskCtx.GetLogger()
+
+ // Jobs added through the multi-branch workflow have _raw_data_table set to "jenkins_api_jobs".
+ // This check works, but it's not very robust. It would be better to use a more explicit check like a "source" column.
+ clauses := []dal.Clause{
+ dal.Select("j.full_name,j.name,j.path,j.class,j.url"),
+ dal.From("_tool_jenkins_jobs as j"),
+ dal.Where(`j.connection_id = ? and j.class = ? and j._raw_data_table = ?`,
+ data.Options.ConnectionId, WORKFLOW_JOB, fmt.Sprintf("_raw_%s", RAW_JOB_TABLE)),
+ }
+ cursor, err := db.Cursor(clauses...)
+ if err != nil {
+ return err
+ }
+ defer cursor.Close()
+
+ iterator, err := helper.NewDalCursorIterator(db, cursor, reflect.TypeOf(SimpleJob{}))
+ if err != nil {
+ return err
+ }
+
+ collectorWithState, err := helper.NewStatefulApiCollector(helper.RawDataSubTaskArgs{
+ Params: JenkinsApiParams{
+ ConnectionId: data.Options.ConnectionId,
+ FullName: data.Options.JobFullName,
+ },
+ Ctx: taskCtx,
+ Table: RAW_BUILD_TABLE,
+ })
+ if err != nil {
+ return err
+ }
+
+ logger.Debug("About to call collectorWithState.InitCollector")
+
+ err = collectorWithState.InitCollector(helper.ApiCollectorArgs{
+ ApiClient: data.ApiClient,
+ Input: iterator,
+ UrlTemplate: "{{ .Input.Path }}api/json",
+ Query: func(reqData *helper.RequestData) (url.Values, errors.Error) {
+ query := url.Values{}
+ treeValue := "allBuilds[timestamp,number,duration,building,estimatedDuration,fullDisplayName,result,actions[lastBuiltRevision[SHA1,branch[name]],remoteUrls,mercurialRevisionNumber,causes[*]],changeSet[kind,revisions[revision]]]"
+ query.Set("tree", treeValue)
+
+ logger.Debug("Query: %v", query)
+
+ return query, nil
+ },
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, errors.Error) {
+ var data struct {
+ Builds []json.RawMessage `json:"allBuilds"`
+ }
+ err := helper.UnmarshalResponse(res, &data)
+ if err != nil {
+ return nil, err
+ }
+
+ builds := make([]json.RawMessage, 0, len(data.Builds))
+ for _, build := range data.Builds {
+ var buildObj map[string]interface{}
+ err := json.Unmarshal(build, &buildObj)
+ if err != nil {
+ return nil, errors.Convert(err)
+ }
+ if buildObj["result"] != nil {
+ builds = append(builds, build)
+ }
+ }
+
+ logger.Debug("Returning this number of builds: %v", len(builds))
+ return builds, nil
+ },
+ AfterResponse: ignoreHTTPStatus404,
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return collectorWithState.Execute()
+}
diff --git a/backend/plugins/jenkins/tasks/build_commit_convertor.go b/backend/plugins/jenkins/tasks/build_commit_convertor.go
index f772e0a31..c1ec84673 100644
--- a/backend/plugins/jenkins/tasks/build_commit_convertor.go
+++ b/backend/plugins/jenkins/tasks/build_commit_convertor.go
@@ -18,6 +18,7 @@ limitations under the License.
package tasks
import (
+ "fmt"
"reflect"
"github.com/apache/incubator-devlake/core/dal"
@@ -45,12 +46,22 @@ func ConvertBuildRepos(taskCtx plugin.SubTaskContext) errors.Error {
dal.Select("*"),
dal.From(&models.JenkinsBuildCommit{}),
dal.Join(`left join _tool_jenkins_builds tjb
- on _tool_jenkins_build_commits.build_name = tjb.full_name
- and _tool_jenkins_build_commits.connection_id = tjb.connection_id`),
- dal.Where(`_tool_jenkins_build_commits.connection_id = ?
- and tjb.job_path = ? and tjb.job_name = ?`,
- data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName),
+ on _tool_jenkins_build_commits.build_name = tjb.full_name
+ and _tool_jenkins_build_commits.connection_id = tjb.connection_id`),
}
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ clauses = append(clauses,
+ dal.Where(`_tool_jenkins_build_commits.connection_id = ?
+ and tjb.full_name like ?`,
+ data.Options.ConnectionId, fmt.Sprintf("%s%%", data.Options.JobFullName)))
+ } else {
+ clauses = append(clauses,
+ dal.Where(`_tool_jenkins_build_commits.connection_id = ?
+ and tjb.job_path = ? and tjb.job_name = ?`,
+ data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName))
+ }
+
cursor, err := db.Cursor(clauses...)
if err != nil {
return err
diff --git a/backend/plugins/jenkins/tasks/build_extractor.go b/backend/plugins/jenkins/tasks/build_extractor.go
index dfa050a21..45f9822cf 100644
--- a/backend/plugins/jenkins/tasks/build_extractor.go
+++ b/backend/plugins/jenkins/tasks/build_extractor.go
@@ -29,8 +29,6 @@ import (
"github.com/apache/incubator-devlake/plugins/jenkins/models"
)
-// this struct should be moved to `gitub_api_common.go`
-
var ExtractApiBuildsMeta = plugin.SubTaskMeta{
Name: "extractApiBuilds",
EntryPoint: ExtractApiBuilds,
@@ -57,15 +55,29 @@ func ExtractApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
return nil, err
}
+ jobName := data.Options.JobName
+ jobPath := data.Options.JobPath
+ fullName := fmt.Sprintf(`%s#%d`, data.Options.JobFullName, body.Number)
+
+ input := &SimpleJob{}
+ err1 := json.Unmarshal(row.Input, input)
+ if err1 == nil && input.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ // For jobs from multi-branch workflow, the job name and path must come from the input,
+ // otherwise it will be set to the multi-branch workflow name and path
+ jobName = input.Name
+ jobPath = input.Path
+ fullName = fmt.Sprintf(`%s#%d`, input.FullName, body.Number)
+ }
+
results := make([]interface{}, 0)
strList := strings.Split(body.Class, ".")
class := strList[len(strList)-1]
build := &models.JenkinsBuild{
ConnectionId: data.Options.ConnectionId,
- JobName: data.Options.JobName,
- JobPath: data.Options.JobPath,
+ JobName: jobName,
+ JobPath: jobPath,
Duration: body.Duration,
- FullName: fmt.Sprintf(`%s#%d`, data.Options.JobFullName, body.Number),
+ FullName: fullName,
EstimatedDuration: body.EstimatedDuration,
Number: body.Number,
Result: body.Result,
diff --git a/backend/plugins/jenkins/tasks/build_stages_enricher.go b/backend/plugins/jenkins/tasks/build_stages_enricher.go
index c3d353a51..3aaf8d27a 100644
--- a/backend/plugins/jenkins/tasks/build_stages_enricher.go
+++ b/backend/plugins/jenkins/tasks/build_stages_enricher.go
@@ -18,6 +18,8 @@ limitations under the License.
package tasks
import (
+ "fmt"
+
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
@@ -35,16 +37,25 @@ var EnrichApiBuildWithStagesMeta = plugin.SubTaskMeta{
func EnrichApiBuildWithStages(taskCtx plugin.SubTaskContext) errors.Error {
data := taskCtx.GetData().(*JenkinsTaskData)
db := taskCtx.GetDal()
+
clauses := []dal.Clause{
dal.Select("tjb.*"),
dal.From(`_tool_jenkins_builds tjb`),
dal.Join(`inner join _tool_jenkins_stages tjs
- on tjs.build_name = tjb.full_name
- and tjs.connection_id = tjb.connection_id`),
- dal.Where(`tjb.connection_id = ?
- and tjb.job_path = ? and tjb.job_name = ?`,
- data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName),
+ on tjs.build_name = tjb.full_name
+ and tjs.connection_id = tjb.connection_id`),
}
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ clauses = append(clauses,
+ dal.Where(`tjb.connection_id = ? and tjb.full_name like ?`,
+ data.Options.ConnectionId, fmt.Sprintf("%s%%", data.Options.JobFullName)))
+ } else {
+ clauses = append(clauses,
+ dal.Where(`tjb.connection_id = ? and tjb.job_path = ? and tjb.job_name = ?`,
+ data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName))
+ }
+
cursor, err := db.Cursor(clauses...)
if err != nil {
return err
diff --git a/backend/plugins/jenkins/tasks/build_collector.go b/backend/plugins/jenkins/tasks/job_collector.go
similarity index 59%
copy from backend/plugins/jenkins/tasks/build_collector.go
copy to backend/plugins/jenkins/tasks/job_collector.go
index 5697c2775..cdb9da4a5 100644
--- a/backend/plugins/jenkins/tasks/build_collector.go
+++ b/backend/plugins/jenkins/tasks/job_collector.go
@@ -29,28 +29,23 @@ import (
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
)
-const RAW_BUILD_TABLE = "jenkins_api_builds"
-
-var CollectApiBuildsMeta = plugin.SubTaskMeta{
- Name: "collectApiBuilds",
- EntryPoint: CollectApiBuilds,
+var CollectApiJobsMeta = plugin.SubTaskMeta{
+ Name: "collectApiJobs",
+ EntryPoint: CollectApiJobs,
EnabledByDefault: true,
- Description: "Collect builds data from jenkins api, supports both timeFilter and diffSync.",
+ Description: "Collect jobs data from multibranch projects using jenkins api, supports both timeFilter and diffSync.",
DomainTypes: []string{plugin.DOMAIN_TYPE_CICD},
}
-type SimpleJob struct {
- Name string
- Path string
-}
+func CollectApiJobs(taskCtx plugin.SubTaskContext) errors.Error {
+ data := taskCtx.GetData().(*JenkinsTaskData)
+ logger := taskCtx.GetLogger()
-type SimpleJenkinsApiBuild struct {
- Number int64
- Timestamp int64 `json:"timestamp"`
-}
+ if data.Options.Class != WORKFLOW_MULTI_BRANCH_PROJECT {
+ logger.Debug("class must be %s, got %s", WORKFLOW_MULTI_BRANCH_PROJECT, data.Options.Class)
+ return nil
+ }
-func CollectApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
- data := taskCtx.GetData().(*JenkinsTaskData)
collector, err := helper.NewStatefulApiCollectorForFinalizableEntity(helper.FinalizableApiCollectorArgs{
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Params: JenkinsApiParams{
@@ -58,56 +53,44 @@ func CollectApiBuilds(taskCtx plugin.SubTaskContext) errors.Error {
FullName: data.Options.JobFullName,
},
Ctx: taskCtx,
- Table: RAW_BUILD_TABLE,
+ Table: RAW_JOB_TABLE,
},
ApiClient: data.ApiClient,
CollectNewRecordsByList: helper.FinalizableApiCollectorListArgs{
- PageSize: 100,
- Concurrency: 10,
FinalizableApiCollectorCommonArgs: helper.FinalizableApiCollectorCommonArgs{
UrlTemplate: fmt.Sprintf("%sjob/%s/api/json", data.Options.JobPath, data.Options.JobName),
Query: func(reqData *helper.RequestData, createdAfter *time.Time) (url.Values, errors.Error) {
query := url.Values{}
- treeValue := fmt.Sprintf(
- "allBuilds[timestamp,number,duration,building,estimatedDuration,fullDisplayName,result,actions[lastBuiltRevision[SHA1,branch[name]],remoteUrls,mercurialRevisionNumber,causes[*]],changeSet[kind,revisions[revision]]]{%d,%d}",
- reqData.Pager.Skip, reqData.Pager.Skip+reqData.Pager.Size)
+ treeValue := "jobs[fullName,name,class,url,color,description]"
query.Set("tree", treeValue)
return query, nil
},
ResponseParser: func(res *http.Response) ([]json.RawMessage, errors.Error) {
var data struct {
- Builds []json.RawMessage `json:"allBuilds"`
+ Jobs []json.RawMessage `json:"jobs"`
}
err := helper.UnmarshalResponse(res, &data)
if err != nil {
return nil, err
}
- builds := make([]json.RawMessage, 0, len(data.Builds))
- for _, build := range data.Builds {
- var buildObj map[string]interface{}
- err := json.Unmarshal(build, &buildObj)
+ jobs := make([]json.RawMessage, 0, len(data.Jobs))
+ for _, job := range data.Jobs {
+ var jobObj map[string]interface{}
+ err := json.Unmarshal(job, &jobObj)
if err != nil {
return nil, errors.Convert(err)
}
- if buildObj["result"] != nil {
- builds = append(builds, build)
+
+ logger.Debug("%v", jobObj)
+ if jobObj["color"] != "notbuilt" && jobObj["color"] != "nobuilt_anime" {
+ jobs = append(jobs, job)
}
}
- return builds, nil
+ return jobs, nil
},
},
- GetCreated: func(item json.RawMessage) (time.Time, errors.Error) {
- b := &SimpleJenkinsApiBuild{}
- err := json.Unmarshal(item, b)
- if err != nil {
- return time.Time{}, errors.BadInput.Wrap(err, "failed to unmarshal jenkins build")
- }
- seconds := b.Timestamp / 1000
- nanos := (b.Timestamp % 1000) * 1000000
- return time.Unix(seconds, nanos), nil
- },
},
})
diff --git a/backend/plugins/jenkins/tasks/stage_extractor.go b/backend/plugins/jenkins/tasks/job_extractor.go
similarity index 65%
copy from backend/plugins/jenkins/tasks/stage_extractor.go
copy to backend/plugins/jenkins/tasks/job_extractor.go
index 96f9cdf76..4f5810e84 100644
--- a/backend/plugins/jenkins/tasks/stage_extractor.go
+++ b/backend/plugins/jenkins/tasks/job_extractor.go
@@ -19,6 +19,8 @@ package tasks
import (
"encoding/json"
+ "strings"
+
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
@@ -27,16 +29,23 @@ import (
// this struct should be moved to `gitub_api_common.go`
-var ExtractApiStagesMeta = plugin.SubTaskMeta{
- Name: "extractApiStages",
- EntryPoint: ExtractApiStages,
+var ExtractApiJobsMeta = plugin.SubTaskMeta{
+ Name: "extractApiJobs",
+ EntryPoint: ExtractApiJobs,
EnabledByDefault: true,
- Description: "Extract raw stages data into tool layer table jenkins_stages",
+ Description: "Extract raw jobs data into tool layer table jenkins_jobs",
DomainTypes: []string{plugin.DOMAIN_TYPE_CICD},
}
-func ExtractApiStages(taskCtx plugin.SubTaskContext) errors.Error {
+func ExtractApiJobs(taskCtx plugin.SubTaskContext) errors.Error {
data := taskCtx.GetData().(*JenkinsTaskData)
+ logger := taskCtx.GetLogger()
+
+ if data.Options.Class != WORKFLOW_MULTI_BRANCH_PROJECT {
+ logger.Debug("class must be %s, got %s", WORKFLOW_MULTI_BRANCH_PROJECT, data.Options.Class)
+ return nil
+ }
+
extractor, err := api.NewApiExtractor(api.ApiExtractorArgs{
RawDataSubTaskArgs: api.RawDataSubTaskArgs{
Params: JenkinsApiParams{
@@ -44,35 +53,23 @@ func ExtractApiStages(taskCtx plugin.SubTaskContext) errors.Error {
FullName: data.Options.JobFullName,
},
Ctx: taskCtx,
- Table: RAW_STAGE_TABLE,
+ Table: RAW_JOB_TABLE,
},
Extract: func(row *api.RawData) ([]interface{}, errors.Error) {
- body := &models.Stage{}
+ body := &models.Job{}
+
err := errors.Convert(json.Unmarshal(row.Data, body))
if err != nil {
return nil, err
}
- input := &SimpleBuild{}
- err = errors.Convert(json.Unmarshal(row.Input, input))
- if err != nil {
- return nil, err
- }
results := make([]interface{}, 0)
+ job := body.ToJenkinsJob()
+ job.ConnectionId = data.Options.ConnectionId
+ job.ScopeConfigId = data.Options.ScopeConfigId
+ job.Path = strings.Replace(body.URL, data.Connection.Endpoint, "", 1)
- stage := &models.JenkinsStage{
- ConnectionId: data.Options.ConnectionId,
- ID: body.ID,
- Name: body.Name,
- ExecNode: body.ExecNode,
- Status: body.Status,
- StartTimeMillis: body.StartTimeMillis,
- DurationMillis: body.DurationMillis,
- PauseDurationMillis: body.PauseDurationMillis,
- BuildName: input.FullName,
- }
-
- results = append(results, stage)
+ results = append(results, job)
return results, nil
},
})
diff --git a/backend/plugins/jenkins/tasks/shared.go b/backend/plugins/jenkins/tasks/shared.go
index cdc42869c..a54f00014 100644
--- a/backend/plugins/jenkins/tasks/shared.go
+++ b/backend/plugins/jenkins/tasks/shared.go
@@ -18,9 +18,10 @@ limitations under the License.
package tasks
import (
+ "net/http"
+
"github.com/apache/incubator-devlake/core/errors"
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
- "net/http"
)
const (
@@ -30,6 +31,9 @@ const (
ABORTED = "ABORTED"
NOT_BUILD = "NOT_BUILD"
UNSTABLE = "UNSTABLE"
+
+ WORKFLOW_MULTI_BRANCH_PROJECT = "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject"
+ WORKFLOW_JOB = "org.jenkinsci.plugins.workflow.job.WorkflowJob"
)
func ignoreHTTPStatus404(res *http.Response) errors.Error {
diff --git a/backend/plugins/jenkins/tasks/stage_collector.go b/backend/plugins/jenkins/tasks/stage_collector.go
index 30501065a..c38e3439b 100644
--- a/backend/plugins/jenkins/tasks/stage_collector.go
+++ b/backend/plugins/jenkins/tasks/stage_collector.go
@@ -43,9 +43,20 @@ var CollectApiStagesMeta = plugin.SubTaskMeta{
type SimpleBuild struct {
Number string
FullName string
+ JobPath string
}
func CollectApiStages(taskCtx plugin.SubTaskContext) errors.Error {
+ data := taskCtx.GetData().(*JenkinsTaskData)
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ return collectMultiBranchBuildApiStages(taskCtx)
+ }
+
+ return collectSingleBuildApiStages(taskCtx)
+}
+
+func collectSingleBuildApiStages(taskCtx plugin.SubTaskContext) errors.Error {
db := taskCtx.GetDal()
data := taskCtx.GetData().(*JenkinsTaskData)
@@ -111,3 +122,67 @@ func CollectApiStages(taskCtx plugin.SubTaskContext) errors.Error {
return apiCollector.Execute()
}
+
+func collectMultiBranchBuildApiStages(taskCtx plugin.SubTaskContext) errors.Error {
+ db := taskCtx.GetDal()
+ data := taskCtx.GetData().(*JenkinsTaskData)
+
+ apiCollector, err := api.NewStatefulApiCollector(api.RawDataSubTaskArgs{
+ Params: JenkinsApiParams{
+ ConnectionId: data.Options.ConnectionId,
+ FullName: data.Options.JobFullName,
+ },
+ Ctx: taskCtx,
+ Table: RAW_STAGE_TABLE,
+ })
+ if err != nil {
+ return err
+ }
+
+ clauses := []dal.Clause{
+ dal.Select("tjb.number,tjb.full_name,tjb.job_path"),
+ dal.From("_tool_jenkins_builds as tjb"),
+ dal.Where(`tjb.connection_id = ? and tjb.full_name like ? and tjb.class = ?`,
+ data.Options.ConnectionId, fmt.Sprintf("%s%%", data.Options.JobFullName), "WorkflowRun"),
+ }
+ if apiCollector.IsIncremental() && apiCollector.GetSince() != nil {
+ clauses = append(clauses, dal.Where(`tjb.start_time >= ?`, apiCollector.GetSince()))
+ }
+ cursor, err := db.Cursor(clauses...)
+ if err != nil {
+ return err
+ }
+ defer cursor.Close()
+
+ iterator, err := api.NewDalCursorIterator(db, cursor, reflect.TypeOf(SimpleBuild{}))
+ if err != nil {
+ return err
+ }
+
+ err = apiCollector.InitCollector(api.ApiCollectorArgs{
+ ApiClient: data.ApiClient,
+ Input: iterator,
+ UrlTemplate: "{{ .Input.JobPath }}{{ .Input.Number }}/wfapi/describe",
+ Query: func(reqData *api.RequestData) (url.Values, errors.Error) {
+ query := url.Values{}
+ return query, nil
+ },
+ ResponseParser: func(res *http.Response) ([]json.RawMessage, errors.Error) {
+ var data struct {
+ Stages []json.RawMessage `json:"stages"`
+ }
+ err := api.UnmarshalResponse(res, &data)
+ if err != nil {
+ return nil, err
+ }
+ return data.Stages, nil
+ },
+ AfterResponse: ignoreHTTPStatus404,
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return apiCollector.Execute()
+}
diff --git a/backend/plugins/jenkins/tasks/stage_convertor.go b/backend/plugins/jenkins/tasks/stage_convertor.go
index 7c57611f3..352eca22a 100644
--- a/backend/plugins/jenkins/tasks/stage_convertor.go
+++ b/backend/plugins/jenkins/tasks/stage_convertor.go
@@ -18,6 +18,7 @@ limitations under the License.
package tasks
import (
+ "fmt"
"reflect"
"time"
@@ -62,6 +63,7 @@ var ConvertStagesMeta = plugin.SubTaskMeta{
func ConvertStages(taskCtx plugin.SubTaskContext) (err errors.Error) {
db := taskCtx.GetDal()
data := taskCtx.GetData().(*JenkinsTaskData)
+
clauses := []dal.Clause{
dal.Select(`tjb.connection_id, tjs.build_name, tjs.id, tjs._raw_data_remark, tjs.name,
tjs._raw_data_id, tjs._raw_data_table, tjs._raw_data_params,
@@ -70,8 +72,16 @@ func ConvertStages(taskCtx plugin.SubTaskContext) (err errors.Error) {
tjb.triggered_by, tjb.building`),
dal.From("_tool_jenkins_stages tjs"),
dal.Join("left join _tool_jenkins_builds tjb on tjs.build_name = tjb.full_name"),
- dal.Where("tjb.connection_id = ? and tjb.job_path = ? and tjb.job_name = ? ",
- data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName),
+ }
+
+ if data.Options.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ clauses = append(clauses,
+ dal.Where(`tjb.connection_id = ? and tjb.full_name like ?`,
+ data.Options.ConnectionId, fmt.Sprintf("%s%%", data.Options.JobFullName)))
+ } else {
+ clauses = append(clauses,
+ dal.Where("tjb.connection_id = ? and tjb.job_path = ? and tjb.job_name = ? ",
+ data.Options.ConnectionId, data.Options.JobPath, data.Options.JobName))
}
cursor, err := db.Cursor(clauses...)
diff --git a/backend/plugins/jenkins/tasks/stage_extractor.go b/backend/plugins/jenkins/tasks/stage_extractor.go
index 96f9cdf76..22da749a8 100644
--- a/backend/plugins/jenkins/tasks/stage_extractor.go
+++ b/backend/plugins/jenkins/tasks/stage_extractor.go
@@ -19,14 +19,13 @@ package tasks
import (
"encoding/json"
+
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
"github.com/apache/incubator-devlake/plugins/jenkins/models"
)
-// this struct should be moved to `gitub_api_common.go`
-
var ExtractApiStagesMeta = plugin.SubTaskMeta{
Name: "extractApiStages",
EntryPoint: ExtractApiStages,
diff --git a/backend/plugins/jenkins/tasks/task_data.go b/backend/plugins/jenkins/tasks/task_data.go
index 3f362002b..29274366e 100644
--- a/backend/plugins/jenkins/tasks/task_data.go
+++ b/backend/plugins/jenkins/tasks/task_data.go
@@ -27,14 +27,17 @@ import (
type JenkinsApiParams models.JenkinsApiParams
type JenkinsOptions struct {
- ConnectionId uint64 `json:"connectionId" mapstructure:"connectionId"`
- ScopeConfigId uint64 `json:"scopeConfigId" mapstructure:"scopeConfigId,omitempty"`
- FullName string `json:"fullName,omitempty" mapstructure:"fullName,omitempty"` // "path1/path2/job name"
- JobFullName string `json:"jobFullName,omitempty" mapstructure:"jobFullName,omitempty"` // "path1/path2/job name"
- JobName string `json:"jobName,omitempty" mapstructure:"jobName,omitempty"` // "job name"
- JobPath string `json:"jobPath,omitempty" mapstructure:"jobPath,omitempty"` // "job/path1/job/path2"
- Tasks []string `json:"tasks,omitempty" mapstructure:"tasks,omitempty"`
- ScopeConfig *models.JenkinsScopeConfig `mapstructure:"scopeConfig" json:"scopeConfig"`
+ ConnectionId uint64 `json:"connectionId" mapstructure:"connectionId"`
+ ScopeConfigId uint64 `json:"scopeConfigId" mapstructure:"scopeConfigId,omitempty"`
+ FullName string `json:"fullName,omitempty" mapstructure:"fullName,omitempty"` // "path1/path2/job name"
+ JobFullName string `json:"jobFullName,omitempty" mapstructure:"jobFullName,omitempty"` // "path1/path2/job name"
+ JobName string `json:"jobName,omitempty" mapstructure:"jobName,omitempty"` // "job name"
+ JobPath string `json:"jobPath,omitempty" mapstructure:"jobPath,omitempty"` // "job/path1/job/path2"
+ Tasks []string `json:"tasks,omitempty" mapstructure:"tasks,omitempty"`
+ ScopeConfig *models.JenkinsScopeConfig `mapstructure:"scopeConfig" json:"scopeConfig"`
+ ConnectionEndpoint string `json:"connectionEndpoint" mapstructure:"connectionEndpoint"`
+ Class string `json:"class" mapstructure:"class,omitempty"`
+ URL string `json:"url" mapstructure:"url,omitempty"`
}
type JenkinsTaskData struct {
@@ -63,6 +66,11 @@ func ValidateTaskOptions(op *JenkinsOptions) (*JenkinsOptions, errors.Error) {
if i := strings.LastIndex(op.JobFullName, `/`); i >= 0 {
op.JobName = op.JobFullName[i+1:]
op.JobPath = `job/` + strings.Join(strings.Split(op.JobFullName[:i], `/`), `/job/`)
+
+ if op.Class == WORKFLOW_MULTI_BRANCH_PROJECT {
+ op.JobPath = `view/all/` + op.JobPath
+ }
+
} else {
op.JobName = op.JobFullName
op.JobPath = `view/all`
@@ -70,5 +78,6 @@ func ValidateTaskOptions(op *JenkinsOptions) (*JenkinsOptions, errors.Error) {
if op.ScopeConfig == nil && op.ScopeConfigId == 0 {
op.ScopeConfig = new(models.JenkinsScopeConfig)
}
+
return op, nil
}