Repository: kubesphere/ks-devops
Pull request #370 (2021-11-23 08:24:27)

Fix the potential panic with git multi-branch source XML parse
Due to this fixing being too minor, I prefer to don't put this into the changelog.

ks-ci-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/370#" title="Author self-approved">LinuxSuRen</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubesphere%2Fks-devops).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[pkg/client/devops/OWNERS](https://github.com/kubesphere/ks-devops/blob/master/pkg/client/devops/OWNERS)~~ [LinuxSuRen]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) Report
> Merging [#370](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (e975922) into [master](https://codecov.io/gh/kubesphere/ks-devops/commit/c96f7386e7cc716e7d2d9269c7376cd56921f07a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (c96f738) will **increase** coverage by `0.06%`.
> The diff coverage is `0.00%`.

[![Impacted file tree graph](https://codecov.io/gh/kubesphere/ks-devops/pull/370/graphs/tree.svg?width=650&height=150&src=pr&token=qSK4RBbyNg&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)

```diff
@@            Coverage Diff            @@
##           master    #370      +/-   ##
=========================================
+ Coverage    7.70%   7.77%   +0.06%     
=========================================
  Files          94      94              
  Lines       21449   21452       +3     
=========================================
+ Hits         1653    1668      +15     
+ Misses      19671   19661      -10     
+ Partials      125     123       -2     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `7.77% <0.00%> (+0.06%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) | Coverage Δ | |
|---|---|---|
| [pkg/client/devops/jenkins/internal/bitbucket.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9kZXZvcHMvamVua2lucy9pbnRlcm5hbC9iaXRidWNrZXQuZ28=) | `3.09% <0.00%> (-0.04%)` | :arrow_down: |
| [pkg/client/devops/jenkins/internal/github.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9kZXZvcHMvamVua2lucy9pbnRlcm5hbC9naXRodWIuZ28=) | `3.06% <0.00%> (-0.04%)` | :arrow_down: |
| [pkg/client/devops/jenkins/internal/gitlab.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9kZXZvcHMvamVua2lucy9pbnRlcm5hbC9naXRsYWIuZ28=) | `3.09% <0.00%> (-0.04%)` | :arrow_down: |
| [...trollers/devopsproject/devopsproject\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvZGV2b3BzcHJvamVjdC9kZXZvcHNwcm9qZWN0X2NvbnRyb2xsZXIuZ28=) | `43.22% <0.00%> (+2.60%)` | :arrow_up: |
| [...rs/devopscredential/devopscredential\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvZGV2b3BzY3JlZGVudGlhbC9kZXZvcHNjcmVkZW50aWFsX2NvbnRyb2xsZXIuZ28=) | `36.48% <0.00%> (+3.37%)` | :arrow_up: |
| [controllers/pipeline/pipeline\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/370/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvcGlwZWxpbmUvcGlwZWxpbmVfY29udHJvbGxlci5nbw==) | `41.91% <0.00%> (+3.67%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Last update [c96f738...e975922](https://codecov.io/gh/kubesphere/ks-devops/pull/370?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere).

LinuxSuRen: > Please try to add some unit tests for this PR.

Of course. Done.
ks-ci-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/370#pullrequestreview-814399707" title="LGTM">JohnNiang</a>*, *<a href="https://github.com/kubesphere/ks-devops/pull/370#" title="Author self-approved">LinuxSuRen</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubesphere%2Fks-devops).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[pkg/client/devops/OWNERS](https://github.com/kubesphere/ks-devops/blob/master/pkg/client/devops/OWNERS)~~ [LinuxSuRen]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
JohnNiang: /label tide/merge-method-squash

Patch:
diff --git a/pkg/client/devops/jenkins/internal/bitbucket.go b/pkg/client/devops/jenkins/internal/bitbucket.go
index 4c90149..547a371 100644
--- a/pkg/client/devops/jenkins/internal/bitbucket.go
+++ b/pkg/client/devops/jenkins/internal/bitbucket.go
@@ -107,16 +107,18 @@ func GetBitbucketServerSourceFromEtree(source *etree.Element) *devopsv1alpha3.Bi
 	if forkPRDiscoverTrait := traits.SelectElement(
 		"com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil {
 		strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text())
-		trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value
-		trust := strings.Split(trustClass, "$")
+		if trustEle := forkPRDiscoverTrait.SelectElement("trust"); trustEle != nil {
+			trustClass := trustEle.SelectAttr("class").Value
+			trust := strings.Split(trustClass, "$")
 
-		if prTrust := BitbucketPRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
-			s.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
-				Strategy: strategyId,
-				Trust:    prTrust.Value(),
+			if prTrust := BitbucketPRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
+				s.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
+					Strategy: strategyId,
+					Trust:    prTrust.Value(),
+				}
+			} else {
+				klog.Warningf("invalid Bitbucket discover PR trust value: %s", trust[1])
 			}
-		} else {
-			klog.Warningf("invalid Bitbucket discover PR trust value: %s", trust[1])
 		}
 
 		if cloneTrait := traits.SelectElement(
diff --git a/pkg/client/devops/jenkins/internal/github.go b/pkg/client/devops/jenkins/internal/github.go
index c72e369..7a1258e 100644
--- a/pkg/client/devops/jenkins/internal/github.go
+++ b/pkg/client/devops/jenkins/internal/github.go
@@ -106,15 +106,17 @@ func GetGithubSourcefromEtree(source *etree.Element) *devopsv1alpha3.GithubSourc
 	if forkPRDiscoverTrait := traits.SelectElement(
 		"org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait"); forkPRDiscoverTrait != nil {
 		strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text())
-		trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value
-		trust := strings.Split(trustClass, "$")
-		if prTrust := GitHubPRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
-			githubSource.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
-				Strategy: strategyId,
-				Trust:    prTrust.Value(),
+		if trustEle := forkPRDiscoverTrait.SelectElement("trust"); trustEle != nil {
+			trustClass := trustEle.SelectAttr("class").Value
+			trust := strings.Split(trustClass, "$")
+			if prTrust := GitHubPRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
+				githubSource.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
+					Strategy: strategyId,
+					Trust:    prTrust.Value(),
+				}
+			} else {
+				klog.Warningf("invalid Gitlab discover PR trust value: %s", trust[1])
 			}
-		} else {
-			klog.Warningf("invalid Gitlab discover PR trust value: %s", trust[1])
 		}
 		if cloneTrait := traits.SelectElement(
 			"jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil {
diff --git a/pkg/client/devops/jenkins/internal/gitlab.go b/pkg/client/devops/jenkins/internal/gitlab.go
index b16e483..961e3d1 100644
--- a/pkg/client/devops/jenkins/internal/gitlab.go
+++ b/pkg/client/devops/jenkins/internal/gitlab.go
@@ -105,15 +105,17 @@ func GetGitlabSourceFromEtree(source *etree.Element) (gitSource *devopsv1alpha3.
 	if forkPRDiscoverTrait := traits.SelectElement(
 		"io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait"); forkPRDiscoverTrait != nil {
 		strategyId, _ := strconv.Atoi(forkPRDiscoverTrait.SelectElement("strategyId").Text())
-		trustClass := forkPRDiscoverTrait.SelectElement("trust").SelectAttr("class").Value
-		trust := strings.Split(trustClass, "$")
-		if prTrust := PRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
-			gitSource.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
-				Strategy: strategyId,
-				Trust:    prTrust.Value(),
+		if trustEle := forkPRDiscoverTrait.SelectElement("trust"); trustEle != nil {
+			trustClass := trustEle.SelectAttr("class").Value
+			trust := strings.Split(trustClass, "$")
+			if prTrust := PRDiscoverTrust(1).ParseFromString(trust[1]); prTrust.IsValid() {
+				gitSource.DiscoverPRFromForks = &devopsv1alpha3.DiscoverPRFromForks{
+					Strategy: strategyId,
+					Trust:    prTrust.Value(),
+				}
+			} else {
+				klog.Warningf("invalid Gitlab discover PR trust value: %s", trust[1])
 			}
-		} else {
-			klog.Warningf("invalid Gitlab discover PR trust value: %s", trust[1])
 		}
 		if cloneTrait := traits.SelectElement(
 			"jenkins.plugins.git.traits.CloneOptionTrait"); cloneTrait != nil {


Test patch:
diff --git a/pkg/client/devops/jenkins/pipeline_internal_test.go b/pkg/client/devops/jenkins/pipeline_internal_test.go
index 261c249..74d0710 100644
--- a/pkg/client/devops/jenkins/pipeline_internal_test.go
+++ b/pkg/client/devops/jenkins/pipeline_internal_test.go
@@ -17,6 +17,8 @@ limitations under the License.
 package jenkins
 
 import (
+	"github.com/stretchr/testify/assert"
+	"kubesphere.io/devops/pkg/client/devops/jenkins/internal"
 	"reflect"
 	"testing"
 
@@ -737,3 +739,458 @@ func Test_MultiBranchPipelineMultibranchTrigger(t *testing.T) {
 	}
 
 }
+
+func TestForkPullRequestDiscoveryTrait(t *testing.T) {
+	// for gitlab cases
+	pipeline, err := parseMultiBranchPipelineConfigXml(noTrustForGitlabJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "gitlab", pipeline.SourceType)
+
+	pipeline, err = parseMultiBranchPipelineConfigXml(withTrustForGitlabJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "gitlab", pipeline.SourceType)
+	assert.Equal(t, internal.PRDiscoverTrustEveryone.Value(), pipeline.GitlabSource.DiscoverPRFromForks.Trust)
+
+	// for github cases
+	pipeline, err = parseMultiBranchPipelineConfigXml(noTrustForGitHubJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "github", pipeline.SourceType)
+
+	pipeline, err = parseMultiBranchPipelineConfigXml(withTrustForGitHubJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "github", pipeline.SourceType)
+	assert.Equal(t, internal.PRDiscoverTrustEveryone.Value(), pipeline.GitHubSource.DiscoverPRFromForks.Trust)
+
+	// for bitbucket cases
+	pipeline, err = parseMultiBranchPipelineConfigXml(noTrustForBitbucketJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "bitbucket_server", pipeline.SourceType)
+
+	pipeline, err = parseMultiBranchPipelineConfigXml(withTrustForBitbucketJobXML)
+	assert.Nil(t, err)
+	assert.Equal(t, "bitbucket_server", pipeline.SourceType)
+	assert.Equal(t, internal.BitbucketPRDiscoverTrustTeamForks.Value(), pipeline.BitbucketServerSource.DiscoverPRFromForks.Trust)
+}
+
+var noTrustForGitlabJobXML = `<?xml version='1.1' encoding='UTF-8'?>
+<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.22">
+  <actions/>
+  <description></description>
+  <properties>
+    <org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig plugin="docker-workflow@1.24">
+      <dockerLabel></dockerLabel>
+      <registry plugin="docker-commons@1.17"/>
+    </org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics>
+    <com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.15">
+      <nonRecursive>false</nonRecursive>
+    </com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
+  </healthMetrics>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.15">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>7</daysToKeep>
+    <numToKeep>5</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <disabled>false</disabled>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.6.2">
+    <data>
+      <jenkins.branch.BranchSource>
+        <source class="io.jenkins.plugins.gitlabbranchsource.GitLabSCMSource" plugin="gitlab-branch-source@1.5.4">
+          <id></id>
+          <serverName>https://gitlab.com</serverName>
+          <projectOwner>linuxsuren1</projectOwner>
+          <projectPath>LinuxSuRen1/learn-pipeline-java</projectPath>
+          <credentialsId></credentialsId>
+          <traits>
+            <io.jenkins.plugins.gitlabbranchsource.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </io.jenkins.plugins.gitlabbranchsource.BranchDiscoveryTrait>
+            <io.jenkins.plugins.gitlabbranchsource.TagDiscoveryTrait/>
+            <io.jenkins.plugins.gitlabbranchsource.OriginMergeRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </io.jenkins.plugins.gitlabbranchsource.OriginMergeRequestDiscoveryTrait>
+            <io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait>
+            <jenkins.scm.impl.trait.RegexSCMHeadFilterTrait plugin="scm-api@2.6.4">
+              <regex>master|v.*</regex>
+            </jenkins.scm.impl.trait.RegexSCMHeadFilterTrait>
+          </traits>
+          <sshRemote>git@gitlab.com:LinuxSuRen1/learn-pipeline-java.git</sshRemote>
+          <httpRemote>https://gitlab.com/LinuxSuRen1/learn-pipeline-java.git</httpRemote>
+          <projectId>23723790</projectId>
+        </source>
+        <strategy class="jenkins.branch.NamedExceptionsBranchPropertyStrategy">
+          <defaultProperties class="empty-list"/>
+          <namedExceptions class="empty-list"/>
+        </strategy>
+      </jenkins.branch.BranchSource>
+    </data>
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
+
+var withTrustForGitlabJobXML = `<?xml version='1.1' encoding='UTF-8'?>
+<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.22">
+  <actions/>
+  <description></description>
+  <properties>
+    <org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig plugin="docker-workflow@1.24">
+      <dockerLabel></dockerLabel>
+      <registry plugin="docker-commons@1.17"/>
+    </org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics>
+    <com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.15">
+      <nonRecursive>false</nonRecursive>
+    </com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
+  </healthMetrics>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.15">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>7</daysToKeep>
+    <numToKeep>5</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <disabled>false</disabled>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.6.2">
+    <data>
+      <jenkins.branch.BranchSource>
+        <source class="io.jenkins.plugins.gitlabbranchsource.GitLabSCMSource" plugin="gitlab-branch-source@1.5.4">
+          <id></id>
+          <serverName>https://gitlab.com</serverName>
+          <projectOwner>linuxsuren1</projectOwner>
+          <projectPath>LinuxSuRen1/learn-pipeline-java</projectPath>
+          <credentialsId></credentialsId>
+          <traits>
+            <io.jenkins.plugins.gitlabbranchsource.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </io.jenkins.plugins.gitlabbranchsource.BranchDiscoveryTrait>
+            <io.jenkins.plugins.gitlabbranchsource.TagDiscoveryTrait/>
+            <io.jenkins.plugins.gitlabbranchsource.OriginMergeRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </io.jenkins.plugins.gitlabbranchsource.OriginMergeRequestDiscoveryTrait>
+            <io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+              <trust class="io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait$TrustEveryone"/>
+            </io.jenkins.plugins.gitlabbranchsource.ForkMergeRequestDiscoveryTrait>
+            <jenkins.scm.impl.trait.RegexSCMHeadFilterTrait plugin="scm-api@2.6.4">
+              <regex>master|v.*</regex>
+            </jenkins.scm.impl.trait.RegexSCMHeadFilterTrait>
+          </traits>
+          <sshRemote>git@gitlab.com:LinuxSuRen1/learn-pipeline-java.git</sshRemote>
+          <httpRemote>https://gitlab.com/LinuxSuRen1/learn-pipeline-java.git</httpRemote>
+          <projectId>23723790</projectId>
+        </source>
+        <strategy class="jenkins.branch.NamedExceptionsBranchPropertyStrategy">
+          <defaultProperties class="empty-list"/>
+          <namedExceptions class="empty-list"/>
+        </strategy>
+      </jenkins.branch.BranchSource>
+    </data>
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
+
+var noTrustForGitHubJobXML = `<?xml version="1.1" encoding="UTF-8"?><org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch">
+  <actions/>
+  <properties>
+    <org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition">
+      <dockerLabel/>
+      <registry plugin="docker-commons"/>
+    </org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics>
+    <com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder">
+      <nonRecursive>false</nonRecursive>
+    </com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
+  </healthMetrics>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <description/>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>7</daysToKeep>
+    <numToKeep>5</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <data>
+      <jenkins.branch.BranchSource>
+        <strategy class="jenkins.branch.NamedExceptionsBranchPropertyStrategy">
+          <defaultProperties class="empty-list"/>
+          <namedExceptions class="empty-list"/>
+        </strategy>
+        <source class="org.jenkinsci.plugins.github_branch_source.GitHubSCMSource" plugin="github-branch-source">
+          <id/>
+          <credentialsId>github</credentialsId>
+          <repoOwner>jenkins-zh</repoOwner>
+          <repository>jenkins-client-java</repository>
+          <traits>
+            <org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.TagDiscoveryTrait/>
+            <jenkins.plugins.git.traits.CloneOptionTrait>
+              <extension class="hudson.plugins.git.extensions.impl.CloneOption">
+                <shallow>false</shallow>
+                <noTags>false</noTags>
+                <honorRefspec>true</honorRefspec>
+                <reference/>
+                <timeout>20</timeout>
+                <depth>1</depth>
+              </extension>
+            </jenkins.plugins.git.traits.CloneOptionTrait>
+          </traits>
+        </source>
+      </jenkins.branch.BranchSource>
+    </data>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
+
+var withTrustForGitHubJobXML = `<?xml version="1.1" encoding="UTF-8"?><org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch">
+  <actions/>
+  <properties>
+    <org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition">
+      <dockerLabel/>
+      <registry plugin="docker-commons"/>
+    </org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics>
+    <com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder">
+      <nonRecursive>false</nonRecursive>
+    </com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
+  </healthMetrics>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <description/>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>7</daysToKeep>
+    <numToKeep>5</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <data>
+      <jenkins.branch.BranchSource>
+        <strategy class="jenkins.branch.NamedExceptionsBranchPropertyStrategy">
+          <defaultProperties class="empty-list"/>
+          <namedExceptions class="empty-list"/>
+        </strategy>
+        <source class="org.jenkinsci.plugins.github_branch_source.GitHubSCMSource" plugin="github-branch-source">
+          <id/>
+          <credentialsId>github</credentialsId>
+          <repoOwner>jenkins-zh</repoOwner>
+          <repository>jenkins-client-java</repository>
+          <traits>
+            <org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+            </org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
+              <strategyId>2</strategyId>
+              <trust class="org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$TrustEveryone"/>
+            </org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
+            <org.jenkinsci.plugins.github__branch__source.TagDiscoveryTrait/>
+            <jenkins.plugins.git.traits.CloneOptionTrait>
+              <extension class="hudson.plugins.git.extensions.impl.CloneOption">
+                <shallow>false</shallow>
+                <noTags>false</noTags>
+                <honorRefspec>true</honorRefspec>
+                <reference/>
+                <timeout>20</timeout>
+                <depth>1</depth>
+              </extension>
+            </jenkins.plugins.git.traits.CloneOptionTrait>
+          </traits>
+        </source>
+      </jenkins.branch.BranchSource>
+    </data>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
+
+var noTrustForBitbucketJobXML = `<?xml version='1.1' encoding='UTF-8'?>
+<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.22">
+  <actions/>
+  <description></description>
+  <properties>
+    <org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig plugin="docker-workflow@1.24">
+      <dockerLabel></dockerLabel>
+      <registry plugin="docker-commons@1.17"/>
+    </org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig>
+    <org.csanchez.jenkins.plugins.kubernetes.KubernetesFolderProperty plugin="kubernetes@1.27.5">
+      <permittedClouds/>
+    </org.csanchez.jenkins.plugins.kubernetes.KubernetesFolderProperty>
+    <org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty plugin="multibranch-action-triggers@1.8.5">
+      <createActionJobsToTrigger></createActionJobsToTrigger>
+      <deleteActionJobsToTrigger></deleteActionJobsToTrigger>
+      <actionJobsToTriggerOnRunDelete></actionJobsToTriggerOnRunDelete>
+      <quitePeriod>0</quitePeriod>
+      <branchIncludeFilter>*</branchIncludeFilter>
+      <branchExcludeFilter></branchExcludeFilter>
+      <additionalParameters/>
+    </org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics/>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.15">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>-1</daysToKeep>
+    <numToKeep>-1</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <disabled>false</disabled>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.6.2">
+    <data>
+      <jenkins.branch.BranchSource>
+        <source class="com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource" plugin="cloudbees-bitbucket-branch-source@2.9.4">
+          <id>edb85ed8-7609-40ac-9bf8-30cdcd762390</id>
+          <serverUrl>https://bitbucket.org</serverUrl>
+          <repoOwner>linuxsuren</repoOwner>
+          <repository>jenkins-cli</repository>
+          <traits>
+            <com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>
+            <com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait>
+            <com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait>
+          </traits>
+        </source>
+        <strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
+          <properties class="empty-list"/>
+        </strategy>
+      </jenkins.branch.BranchSource>
+    </data>
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`
+
+var withTrustForBitbucketJobXML = `<?xml version='1.1' encoding='UTF-8'?>
+<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.22">
+  <actions/>
+  <description></description>
+  <properties>
+    <org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig plugin="docker-workflow@1.24">
+      <dockerLabel></dockerLabel>
+      <registry plugin="docker-commons@1.17"/>
+    </org.jenkinsci.plugins.docker.workflow.declarative.FolderConfig>
+    <org.csanchez.jenkins.plugins.kubernetes.KubernetesFolderProperty plugin="kubernetes@1.27.5">
+      <permittedClouds/>
+    </org.csanchez.jenkins.plugins.kubernetes.KubernetesFolderProperty>
+    <org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty plugin="multibranch-action-triggers@1.8.5">
+      <createActionJobsToTrigger></createActionJobsToTrigger>
+      <deleteActionJobsToTrigger></deleteActionJobsToTrigger>
+      <actionJobsToTriggerOnRunDelete></actionJobsToTriggerOnRunDelete>
+      <quitePeriod>0</quitePeriod>
+      <branchIncludeFilter>*</branchIncludeFilter>
+      <branchExcludeFilter></branchExcludeFilter>
+      <additionalParameters/>
+    </org.jenkinsci.plugins.workflow.multibranch.PipelineTriggerProperty>
+  </properties>
+  <folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </folderViews>
+  <healthMetrics/>
+  <icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.6.2">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </icon>
+  <orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.15">
+    <pruneDeadBranches>true</pruneDeadBranches>
+    <daysToKeep>-1</daysToKeep>
+    <numToKeep>-1</numToKeep>
+  </orphanedItemStrategy>
+  <triggers/>
+  <disabled>false</disabled>
+  <sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.6.2">
+    <data>
+      <jenkins.branch.BranchSource>
+        <source class="com.cloudbees.jenkins.plugins.bitbucket.BitbucketSCMSource" plugin="cloudbees-bitbucket-branch-source@2.9.4">
+          <id>edb85ed8-7609-40ac-9bf8-30cdcd762390</id>
+          <serverUrl>https://bitbucket.org</serverUrl>
+          <repoOwner>linuxsuren</repoOwner>
+          <repository>jenkins-cli</repository>
+          <traits>
+            <com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </com.cloudbees.jenkins.plugins.bitbucket.BranchDiscoveryTrait>
+            <com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait>
+              <strategyId>1</strategyId>
+            </com.cloudbees.jenkins.plugins.bitbucket.OriginPullRequestDiscoveryTrait>
+            <com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait>
+              <strategyId>1</strategyId>
+              <trust class="com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait$TrustTeamForks"/>
+            </com.cloudbees.jenkins.plugins.bitbucket.ForkPullRequestDiscoveryTrait>
+          </traits>
+        </source>
+        <strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
+          <properties class="empty-list"/>
+        </strategy>
+      </jenkins.branch.BranchSource>
+    </data>
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+  </sources>
+  <factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
+    <owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
+    <scriptPath>Jenkinsfile</scriptPath>
+  </factory>
+</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>`