Repository: kubesphere/ks-devops
Pull request #795 (2022-08-22 06:00:35)

Remove unused code lines
<!-- Thanks for sending a pull request! Here are some tips for you:

1. If you want **faster** PR reviews, read how: https://github.com/kubesphere/community/blob/master/developer-guide/development/the-pr-author-guide-to-getting-through-code-review.md
2. In case you want to know how your PR got reviewed, read: https://github.com/kubesphere/community/blob/master/developer-guide/development/code-review-guide.md
3. Here are some coding conventions followed by the KubeSphere community: https://github.com/kubesphere/community/blob/master/developer-guide/development/coding-conventions.md
4. Additional open-source best practice: https://github.com/LinuxSuRen/open-source-best-practice
-->

### What type of PR is this?
<!-- 
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design
/kind chore

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

### What this PR does / why we need it:

### Which issue(s) this PR fixes:
<!--
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
Please leave it or change # to be None if there is no corresponding issue that exists
-->
Fixes #

upstream is https://github.com/jenkins-zh/jenkins-client/pull/57

### Special notes for reviewers:
<!--
You can use the following command to let the DevOps SIG members help you to review your PR.
/cc @kubesphere/sig-devops 
And please avoid cc any individual.
-->
Please check the following list before waiting reviewers:

- [ ] Already committed the CRD files to [the Helm Chart](https://github.com/kubesphere-sigs/ks-devops-helm-chart/) if you created some new CRDs
- [ ] Already [added the permission](https://github.com/kubesphere/ks-installer/blob/9e063b085a0e43fdb3d0d9e3e7f4149146f14b9c/roles/ks-core/prepare/files/ks-init/role-templates.yaml) for the new API
- [ ] Already added the RBAC markers for the new controllers

### Does this PR introduce a user-facing change??
<!--
If no, just write "None" in the release-note block below.
If yes, a release note is required:
Enter your extended-release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

Please keep the note be same as your PR title if you believe it should be in the release notes.
-->
```release-note
None
```


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

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please ask for approval from **linuxsuren** after the PR has been reviewed.

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

<details open>
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)**
- **[pkg/models/devops/OWNERS](https://github.com/kubesphere/ks-devops/blob/master/pkg/models/devops/OWNERS)**

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":["linuxsuren"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/795?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) Report
> Merging [#795](https://codecov.io/gh/kubesphere/ks-devops/pull/795?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (cecc3d4) into [master](https://codecov.io/gh/kubesphere/ks-devops/commit/9208f966dd61e133334180fa86ec4a9eadeea610?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (9208f96) will **increase** coverage by `0.42%`.
> The diff coverage is `n/a`.

```diff
@@            Coverage Diff             @@
##           master     #795      +/-   ##
==========================================
+ Coverage   51.19%   51.62%   +0.42%     
==========================================
  Files         171      171              
  Lines       10141    10057      -84     
==========================================
  Hits         5192     5192              
+ Misses       4658     4573      -85     
- Partials      291      292       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `51.62% <ø> (+0.42%)` | :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/795?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/build.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9kZXZvcHMvamVua2lucy9idWlsZC5nbw==) | `0.00% <ø> (ø)` | |
| [pkg/client/devops/jenkins/job.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9kZXZvcHMvamVua2lucy9qb2IuZ28=) | `0.00% <ø> (ø)` | |
| [pkg/models/devops/common.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL21vZGVscy9kZXZvcHMvY29tbW9uLmdv) | `100.00% <ø> (ø)` | |
| [pkg/models/devops/devops.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL21vZGVscy9kZXZvcHMvZGV2b3BzLmdv) | `25.36% <ø> (ø)` | |
| [.../jenkins/devopsproject/devopsproject\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvamVua2lucy9kZXZvcHNwcm9qZWN0L2Rldm9wc3Byb2plY3RfY29udHJvbGxlci5nbw==) | `40.62% <0.00%> (-2.61%)` | :arrow_down: |
| [...ns/devopscredential/devopscredential\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/795/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvamVua2lucy9kZXZvcHNjcmVkZW50aWFsL2Rldm9wc2NyZWRlbnRpYWxfY29udHJvbGxlci5nbw==) | `36.73% <0.00%> (+3.40%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)

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

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please ask for approval from **linuxsuren** after the PR has been reviewed.

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

<details open>
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)**
- **[pkg/kapis/devops/v1alpha2/OWNERS](https://github.com/kubesphere/ks-devops/blob/master/pkg/kapis/devops/v1alpha2/OWNERS)**
- **[pkg/models/devops/OWNERS](https://github.com/kubesphere/ks-devops/blob/master/pkg/models/devops/OWNERS)**

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":["linuxsuren"]} -->
ks-ci-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please ask for approval from **linuxsuren** after the PR has been reviewed.

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

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

- **[OWNERS](https://github.com/kubesphere/ks-devops/blob/master/OWNERS)**

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":["linuxsuren"]} -->

Patch:
diff --git a/go.mod b/go.mod
index eef9e7e..8c1e3e2 100644
--- a/go.mod
+++ b/go.mod
@@ -139,3 +139,5 @@ replace (
 	github.com/kubesphere/sonargo => github.com/kubesphere/sonargo v0.0.2
 	golang.org/x/text => golang.org/x/text v0.3.7
 )
+
+replace github.com/jenkins-zh/jenkins-client => github.com/linuxsuren/jenkins-client v0.0.0-20220823083928-d2b2288b88d8
diff --git a/go.sum b/go.sum
index 3f73ed5..82b14c1 100644
--- a/go.sum
+++ b/go.sum
@@ -389,8 +389,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i
 github.com/jenkins-x/go-scm v1.11.19 h1:H4CzaM/C/0QcCVLDh603Q6Bv4hqU4G3De2yQntWubqg=
 github.com/jenkins-x/go-scm v1.11.19/go.mod h1:eIcty4+tf6E7ycGOg0cUqnaLP+1LH1Z8zncQFQqRa3E=
 github.com/jenkins-zh/jenkins-cli v0.0.32/go.mod h1:uE1mH9PNITrg0sugv6HXuM/CSddg0zxXoYu3w57I3JY=
-github.com/jenkins-zh/jenkins-client v0.0.13 h1:MIBq36M9RYaJTVOE9sHmD/NOXzf4el9qZ4RRr/1/Lxw=
-github.com/jenkins-zh/jenkins-client v0.0.13/go.mod h1:ICBk7OOoTafVP//f/VfKZ34c0ff8vJwVnOsF9btiMYU=
 github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220811083317-bb6f87a3f866 h1:MQwSe0z1hju5X9c5BEfQAvkb4Fub1ZoHLo+ZLJ7mAyo=
 github.com/jenkins-zh/jenkins-client/pkg/k8s v0.0.0-20220811083317-bb6f87a3f866/go.mod h1:zetE8JfNmxkot7OCNXJyS/QwxFnfcUFzrs/jg4U2gAw=
 github.com/jenkins-zh/jenkins-formulas v0.0.5/go.mod h1:zS8fm8u5L6FcjZM0QznXsLV9T2UtSVK+hT6Sm76iUZ4=
@@ -448,6 +446,8 @@ github.com/linuxsuren/http-downloader v0.0.2-0.20201207132639-19888a6beaec/go.mo
 github.com/linuxsuren/http-downloader v0.0.6/go.mod h1:xxgh2OE7WGL9TwDE9L8Gh7Lqq9fFPuHbh5tofUitEfE=
 github.com/linuxsuren/http-downloader v0.0.29 h1:GJUoybR4SViarPfX2xipq0unUssiuB9qrSSoDDW1jao=
 github.com/linuxsuren/http-downloader v0.0.29/go.mod h1:bniEqpLyyydtCTDyjo3nco6LD2F90ruPH87fuqAznQg=
+github.com/linuxsuren/jenkins-client v0.0.0-20220823083928-d2b2288b88d8 h1:9wEvfOXaL0Ip2+I0zUlUGvcUAjqJMueFZWzdRUqaPbs=
+github.com/linuxsuren/jenkins-client v0.0.0-20220823083928-d2b2288b88d8/go.mod h1:T8M/g0p7jjx0NBwN6gNqsAAmT1P3B70GBBJJgsX9kLw=
 github.com/linuxsuren/unstructured v0.0.1 h1:ilUA8MUYbR6l9ebo/YPV2bKqlf62bzQursDSE+j00iU=
 github.com/linuxsuren/unstructured v0.0.1/go.mod h1:KH6aTj+FegzGBzc1vS6mzZx3/duhTUTEVyW5sO7p4as=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
diff --git a/pkg/client/devops/fake/fakedevops.go b/pkg/client/devops/fake/fakedevops.go
index 7835cd7..12787ef 100644
--- a/pkg/client/devops/fake/fakedevops.go
+++ b/pkg/client/devops/fake/fakedevops.go
@@ -305,12 +305,6 @@ func (d *Devops) CheckScriptCompile(projectName, pipelineName string, httpParame
 func (d *Devops) CheckCron(projectName string, httpParameters *devops.HttpParameters) (*devops.CheckCronRes, error) {
 	return nil, nil
 }
-func (d *Devops) ToJenkinsfile(httpParameters *devops.HttpParameters) (*devops.ResJenkinsfile, error) {
-	return nil, nil
-}
-func (d *Devops) ToJSON(httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
-	return nil, nil
-}
 
 // CredentialOperator
 func (d *Devops) CreateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
@@ -395,9 +389,6 @@ func (d *Devops) GetCredentialInProject(projectId, id string) (*devops.Credentia
 	}
 	return &devops.Credential{Id: id}, nil
 }
-func (d *Devops) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
-	return nil, nil
-}
 func (d *Devops) DeleteCredentialInProject(projectId, id string) (string, error) {
 	if _, ok := d.Credentials[projectId][id]; !ok {
 		err := &devops.ErrorResponse{
@@ -450,7 +441,9 @@ func (d *Devops) CreateProjectPipeline(projectId string, pipeline *devopsv1alpha
 		err := fmt.Errorf("pipeline name [%s] has been used", pipeline.Name)
 		return "", restful.NewError(http.StatusConflict, err.Error())
 	}
-	d.Pipelines[projectId][pipeline.Name] = pipeline
+	if d.Pipelines[projectId] != nil {
+		d.Pipelines[projectId][pipeline.Name] = pipeline
+	}
 	return "", nil
 }
 
diff --git a/pkg/client/devops/jclient/credential.go b/pkg/client/devops/jclient/credential.go
index 80c09a4..a50c8d7 100644
--- a/pkg/client/devops/jclient/credential.go
+++ b/pkg/client/devops/jclient/credential.go
@@ -17,18 +17,28 @@ limitations under the License.
 package jclient
 
 import (
+	jcredential "github.com/jenkins-zh/jenkins-client/pkg/credential"
 	v1 "k8s.io/api/core/v1"
 	"kubesphere.io/devops/pkg/client/devops"
+	"kubesphere.io/devops/pkg/client/devops/util"
 )
 
 // CreateCredentialInProject creates a credential, then returns the ID
-func (j *JenkinsClient) CreateCredentialInProject(projectID string, credential *v1.Secret) (string, error) {
-	return j.jenkins.CreateCredentialInProject(projectID, credential)
+func (j *JenkinsClient) CreateCredentialInProject(projectID string, credential *v1.Secret) (id string, err error) {
+	client := j.getClient()
+
+	var cre interface{}
+	if cre, err = util.ConvertSecretToCredential(credential); err != nil {
+		return "", err
+	}
+	return "", client.CreateInFolder(projectID, cre)
 }
 
 // UpdateCredentialInProject updates a credential
-func (j *JenkinsClient) UpdateCredentialInProject(projectID string, credential *v1.Secret) (string, error) {
-	return j.jenkins.UpdateCredentialInProject(projectID, credential)
+func (j *JenkinsClient) UpdateCredentialInProject(projectID string, credential *v1.Secret) (id string, err error) {
+	client := j.getClient()
+	err = client.UpdateInFolder(projectID, credential.GetName(), credential)
+	return
 }
 
 // GetCredentialInProject returns a credential
@@ -38,5 +48,10 @@ func (j *JenkinsClient) GetCredentialInProject(projectID, id string) (*devops.Cr
 
 // DeleteCredentialInProject deletes a credential
 func (j *JenkinsClient) DeleteCredentialInProject(projectID, id string) (string, error) {
-	return j.jenkins.DeleteCredentialInProject(projectID, id)
+	client := j.getClient()
+	return id, client.DeleteInFolder(projectID, id)
+}
+
+func (j *JenkinsClient) getClient() *jcredential.CredentialsManager {
+	return &jcredential.CredentialsManager{JenkinsCore: j.Core}
 }
diff --git a/pkg/client/devops/jclient/pipeline.go b/pkg/client/devops/jclient/pipeline.go
index 8217421..f1a5215 100644
--- a/pkg/client/devops/jclient/pipeline.go
+++ b/pkg/client/devops/jclient/pipeline.go
@@ -23,7 +23,6 @@ import (
 	"strconv"
 
 	"github.com/jenkins-zh/jenkins-client/pkg/artifact"
-
 	"kubesphere.io/devops/pkg/client/devops"
 )
 
@@ -226,13 +225,3 @@ func (j *JenkinsClient) CheckScriptCompile(projectName, pipelineName string, htt
 func (j *JenkinsClient) CheckCron(projectName string, httpParameters *devops.HttpParameters) (*devops.CheckCronRes, error) {
 	return j.jenkins.CheckCron(projectName, httpParameters)
 }
-
-// ToJenkinsfile sends a request to turn to jenkinsfile
-func (j *JenkinsClient) ToJenkinsfile(httpParameters *devops.HttpParameters) (*devops.ResJenkinsfile, error) {
-	return j.jenkins.ToJenkinsfile(httpParameters)
-}
-
-// ToJSON sends a request to turn JSOn
-func (j *JenkinsClient) ToJSON(httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
-	return j.jenkins.ToJSON(httpParameters)
-}
diff --git a/pkg/client/devops/jenkins/build.go b/pkg/client/devops/jenkins/build.go
index cc7a86a..eac96e1 100644
--- a/pkg/client/devops/jenkins/build.go
+++ b/pkg/client/devops/jenkins/build.go
@@ -231,78 +231,6 @@ func (b *Build) GetInjectedEnvVars() (map[string]string, error) {
 	return envVars.EnvMap, nil
 }
 
-func (b *Build) GetDownstreamBuilds() ([]*Build, error) {
-	result := make([]*Build, 0)
-	downstreamJobs, err := b.Job.GetDownstreamJobs()
-	if err != nil {
-		return nil, err
-	}
-	for _, job := range downstreamJobs {
-		allBuildIDs, err := job.GetAllBuildIds()
-		if err != nil {
-			return nil, err
-		}
-		for _, buildID := range allBuildIDs {
-			build, err := job.GetBuild(buildID.Number)
-			if err != nil {
-				return nil, err
-			}
-			upstreamBuild, _ := build.GetUpstreamBuild()
-			// cannot compare only id, it can be from different job
-			if b.GetUrl() == upstreamBuild.GetUrl() {
-				result = append(result, build)
-				break
-			}
-		}
-	}
-	return result, nil
-}
-
-func (b *Build) GetUpstreamJob() (*Job, error) {
-	causes, err := b.GetCauses()
-	if err != nil {
-		return nil, err
-	}
-	if len(causes) > 0 {
-		if job, ok := causes[0]["upstreamProject"]; ok {
-			return b.Jenkins.GetJob(job.(string))
-		}
-	}
-	return nil, errors.New("Unable to get Upstream Job")
-}
-
-func (b *Build) GetUpstreamBuildNumber() (int64, error) {
-	causes, err := b.GetCauses()
-	if err != nil {
-		return 0, err
-	}
-	if len(causes) > 0 {
-		if build, ok := causes[0]["upstreamBuild"]; ok {
-			switch t := build.(type) {
-			default:
-				return t.(int64), nil
-			case float64:
-				return int64(t), nil
-			}
-		}
-	}
-	return 0, nil
-}
-
-func (b *Build) GetUpstreamBuild() (*Build, error) {
-	job, err := b.GetUpstreamJob()
-	if err != nil {
-		return nil, err
-	}
-	if job != nil {
-		buildNumber, err := b.GetUpstreamBuildNumber()
-		if err == nil {
-			return job.GetBuild(buildNumber)
-		}
-	}
-	return nil, errors.New("Build not found")
-}
-
 func (b *Build) GetResultSet() (*TestResult, error) {
 
 	url := b.Base + "/testReport"
diff --git a/pkg/client/devops/jenkins/credential.go b/pkg/client/devops/jenkins/credential.go
index 43b9dc0..20bd194 100644
--- a/pkg/client/devops/jenkins/credential.go
+++ b/pkg/client/devops/jenkins/credential.go
@@ -19,151 +19,11 @@ import (
 	"net/http"
 	"strconv"
 
-	"github.com/emicklei/go-restful"
 	v1 "k8s.io/api/core/v1"
-	"k8s.io/klog/v2"
-
-	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
 
 	"kubesphere.io/devops/pkg/client/devops"
 )
 
-const SSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
-const DirectSSHCrenditalStaplerClass = "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource"
-const UsernamePassswordCredentialStaplerClass = "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"
-const SecretTextCredentialStaplerClass = "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl"
-const KubeconfigCredentialStaplerClass = "com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials"
-const DirectKubeconfigCredentialStaperClass = "com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials$DirectEntryKubeconfigSource"
-const GLOBALScope = "GLOBAL"
-
-type UsernamePasswordCredential struct {
-	Scope        string `json:"scope"`
-	Id           string `json:"id"`
-	Username     string `json:"username"`
-	Password     string `json:"password"`
-	Description  string `json:"description"`
-	StaplerClass string `json:"stapler-class"`
-}
-
-type SshCredential struct {
-	Scope        string           `json:"scope"`
-	Id           string           `json:"id"`
-	Username     string           `json:"username"`
-	Passphrase   string           `json:"passphrase"`
-	KeySource    PrivateKeySource `json:"privateKeySource"`
-	Description  string           `json:"description"`
-	StaplerClass string           `json:"stapler-class"`
-}
-
-type SecretTextCredential struct {
-	Scope        string `json:"scope"`
-	Id           string `json:"id"`
-	Secret       string `json:"secret"`
-	Description  string `json:"description"`
-	StaplerClass string `json:"stapler-class"`
-}
-
-type KubeconfigCredential struct {
-	Scope            string           `json:"scope"`
-	Id               string           `json:"id"`
-	Description      string           `json:"description"`
-	KubeconfigSource KubeconfigSource `json:"kubeconfigSource"`
-	StaplerClass     string           `json:"stapler-class"`
-}
-
-type PrivateKeySource struct {
-	StaplerClass string `json:"stapler-class"`
-	PrivateKey   string `json:"privateKey"`
-}
-
-type KubeconfigSource struct {
-	StaplerClass string `json:"stapler-class"`
-	Content      string `json:"content"`
-}
-
-type CredentialResponse struct {
-	Id          string `json:"id"`
-	TypeName    string `json:"typeName"`
-	DisplayName string `json:"displayName"`
-	Fingerprint *struct {
-		FileName string `json:"file_name,omitempty" description:"Credential's display name and description"`
-		Hash     string `json:"hash,omitempty" description:"Credential's hash"`
-		Usage    []*struct {
-			Name   string `json:"name,omitempty" description:"Jenkins pipeline full name"`
-			Ranges struct {
-				Ranges []*struct {
-					Start int `json:"start,omitempty" description:"Start build number"`
-					End   int `json:"end,omitempty" description:"End build number"`
-				} `json:"ranges,omitempty"`
-			} `json:"ranges,omitempty" description:"The build number of all pipelines that use this credential"`
-		} `json:"usage,omitempty" description:"all usage of Credential"`
-	} `json:"fingerprint,omitempty" description:"usage of the Credential"`
-	Description string `json:"description,omitempty"`
-	Domain      string `json:"domain"`
-}
-
-func NewSshCredential(secret *v1.Secret) *SshCredential {
-	id := secret.Name
-	username := string(secret.Data[devopsv1alpha3.SSHAuthUsernameKey])
-	passphrase := string(secret.Data[devopsv1alpha3.SSHAuthPassphraseKey])
-	privatekey := string(secret.Data[devopsv1alpha3.SSHAuthPrivateKey])
-
-	keySource := PrivateKeySource{
-		StaplerClass: DirectSSHCrenditalStaplerClass,
-		PrivateKey:   privatekey,
-	}
-
-	return &SshCredential{
-		Scope:        GLOBALScope,
-		Id:           id,
-		Username:     username,
-		Passphrase:   passphrase,
-		KeySource:    keySource,
-		StaplerClass: SSHCrenditalStaplerClass,
-	}
-}
-
-func NewUsernamePasswordCredential(secret *v1.Secret) *UsernamePasswordCredential {
-	id := secret.Name
-	username := string(secret.Data[devopsv1alpha3.BasicAuthUsernameKey])
-	password := string(secret.Data[devopsv1alpha3.BasicAuthPasswordKey])
-	return &UsernamePasswordCredential{
-		Scope:        GLOBALScope,
-		Id:           id,
-		Username:     username,
-		Password:     password,
-		StaplerClass: UsernamePassswordCredentialStaplerClass,
-	}
-}
-
-func NewSecretTextCredential(secret *v1.Secret) *SecretTextCredential {
-	id := secret.Name
-	secretContent := string(secret.Data[devopsv1alpha3.SecretTextSecretKey])
-	return &SecretTextCredential{
-		Scope:        GLOBALScope,
-		Id:           id,
-		Secret:       secretContent,
-		StaplerClass: SecretTextCredentialStaplerClass,
-	}
-}
-
-func NewKubeconfigCredential(secret *v1.Secret) *KubeconfigCredential {
-	id := secret.Name
-	secretContent := string(secret.Data[devopsv1alpha3.KubeConfigSecretKey])
-
-	credentialSource := KubeconfigSource{
-		StaplerClass: DirectKubeconfigCredentialStaperClass,
-		Content:      secretContent,
-	}
-
-	return &KubeconfigCredential{
-		Scope:            GLOBALScope,
-		Id:               id,
-		KubeconfigSource: credentialSource,
-		StaplerClass:     KubeconfigCredentialStaplerClass,
-	}
-}
-
 func (j *Jenkins) GetCredentialInProject(projectId, id string) (*devops.Credential, error) {
 	responseStruct := &devops.Credential{}
 
@@ -184,118 +44,20 @@ func (j *Jenkins) GetCredentialInProject(projectId, id string) (*devops.Credenti
 	return responseStruct, nil
 }
 
-func (j *Jenkins) GetCredentialsInProject(projectId string) ([]*devops.Credential, error) {
-	domain := "_"
-	var responseStruct = &struct {
-		Credentials []*devops.Credential `json:"credentials"`
-	}{}
-	response, err := j.Requester.GetJSON(
-		fmt.Sprintf("/job/%s/credentials/store/folder/domain/_", projectId),
-		responseStruct, map[string]string{
-			"depth": "2",
-		})
-	if err != nil {
-		return nil, err
-	}
-	if response.StatusCode != http.StatusOK {
-		return nil, errors.New(strconv.Itoa(response.StatusCode))
-	}
-	for _, credential := range responseStruct.Credentials {
-		credential.Domain = domain
-	}
-	return responseStruct.Credentials, nil
-
-}
-
 func (j *Jenkins) CreateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
-
-	var request interface{}
-	responseString := ""
-	switch credential.Type {
-	case devopsv1alpha3.SecretTypeBasicAuth:
-		request = NewUsernamePasswordCredential(credential)
-	case devopsv1alpha3.SecretTypeSSHAuth:
-		request = NewSshCredential(credential)
-	case devopsv1alpha3.SecretTypeSecretText:
-		request = NewSecretTextCredential(credential)
-	case devopsv1alpha3.SecretTypeKubeConfig:
-		request = NewKubeconfigCredential(credential)
-	default:
-		err := fmt.Errorf("error unsupport credential type")
-		klog.Errorf("%+v", err)
-		return "", restful.NewError(http.StatusBadRequest, err.Error())
-	}
-
-	response, err := j.Requester.PostForm(
-		fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/createCredentials", projectId),
-		nil, &responseString, map[string]string{
-			"json": makeJson(map[string]interface{}{
-				"credentials": request,
-			}),
-		})
-	if err != nil {
-		return "", err
-	}
-
-	// the Jenkins API `/job/{jobName}/credentials/store/folder/domain/_/createCredentials`
-	// under a special version of Jenkins, the response status code is `http.StatusFound`
-	// In order to be applicable to multiple versions of Jenkins,
-	// here you need to verify `http.StatusOK` and `http.StatusFound`
-	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusFound {
-		return "", errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return credential.Name, nil
+	// use pkg/client/devops/jclient/credential.go instead
+	panic(nil)
 }
 
 func (j *Jenkins) UpdateCredentialInProject(projectId string, credential *v1.Secret) (string, error) {
-
-	requestContent := ""
-	switch credential.Type {
-	case devopsv1alpha3.SecretTypeBasicAuth:
-		requestStruct := NewUsernamePasswordCredential(credential)
-		requestContent = makeJson(requestStruct)
-	case devopsv1alpha3.SecretTypeSSHAuth:
-		requestStruct := NewSshCredential(credential)
-		requestContent = makeJson(requestStruct)
-	case devopsv1alpha3.SecretTypeSecretText:
-		requestStruct := NewSecretTextCredential(credential)
-		requestContent = makeJson(requestStruct)
-	case devopsv1alpha3.SecretTypeKubeConfig:
-		requestStruct := NewKubeconfigCredential(credential)
-		requestContent = makeJson(requestStruct)
-	default:
-		err := fmt.Errorf("error unsupport credential type")
-		klog.Errorf("%+v", err)
-		return "", restful.NewError(http.StatusBadRequest, err.Error())
-	}
-	response, err := j.Requester.PostForm(
-		fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/updateSubmit", projectId, credential.Name),
-		nil, nil, map[string]string{
-			"json": requestContent,
-		})
-	if err != nil {
-		return "", err
-	}
-
-	// the Jenkins API `/job/{jobName}/credentials/store/folder/domain/_/credential/{credentialName}/updateSubmit`
-	// under a special version of Jenkins, the response status code is `http.StatusFound`
-	// In order to be applicable to multiple versions of Jenkins,
-	// here you need to verify `http.StatusOK` and `http.StatusFound`
-	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusFound {
-		return "", errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return credential.Name, nil
+	// use pkg/client/devops/jclient/credential.go instead
+	panic(nil)
 }
 
+// DeleteCredentialInProject deletes credential
+//
+// Deprecated
 func (j *Jenkins) DeleteCredentialInProject(projectId, id string) (string, error) {
-	response, err := j.Requester.Post(
-		fmt.Sprintf("/job/%s/credentials/store/folder/domain/_/credential/%s/doDelete", projectId, id),
-		nil, nil, nil)
-	if err != nil {
-		return "", err
-	}
-	if response.StatusCode != http.StatusOK {
-		return "", errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return id, nil
+	// use pkg/client/devops/jclient/credential.go instead
+	panic(nil)
 }
diff --git a/pkg/client/devops/jenkins/jenkins.go b/pkg/client/devops/jenkins/jenkins.go
index 7e98120..90d6dbc 100644
--- a/pkg/client/devops/jenkins/jenkins.go
+++ b/pkg/client/devops/jenkins/jenkins.go
@@ -620,26 +620,6 @@ func (j *Jenkins) CheckCron(projectName string, httpParameters *devops.HttpParam
 	return res, err
 }
 
-func (j *Jenkins) ToJenkinsfile(httpParameters *devops.HttpParameters) (*devops.ResJenkinsfile, error) {
-	PipelineOjb := &Pipeline{
-		HttpParameters: httpParameters,
-		Jenkins:        j,
-		Path:           ToJenkinsfileUrl,
-	}
-	res, err := PipelineOjb.ToJenkinsfile()
-	return res, err
-}
-
-func (j *Jenkins) ToJSON(httpParameters *devops.HttpParameters) (map[string]interface{}, error) {
-	PipelineOjb := &Pipeline{
-		HttpParameters: httpParameters,
-		Jenkins:        j,
-		Path:           ToJsonUrl,
-	}
-	res, err := PipelineOjb.ToJSON()
-	return res, err
-}
-
 // Creates a new Jenkins Instance
 // Optional parameters are: client, username, password
 // After creating an instance call init method.
diff --git a/pkg/client/devops/jenkins/job.go b/pkg/client/devops/jenkins/job.go
index 7222567..865cf73 100644
--- a/pkg/client/devops/jenkins/job.go
+++ b/pkg/client/devops/jenkins/job.go
@@ -212,88 +212,6 @@ func (j *Job) GetAllBuildStatus() ([]JobBuildStatus, error) {
 	return buildsResp.Builds, nil
 }
 
-func (j *Job) GetUpstreamJobsMetadata() []InnerJob {
-	return j.Raw.UpstreamProjects
-}
-
-func (j *Job) GetDownstreamJobsMetadata() []InnerJob {
-	return j.Raw.DownstreamProjects
-}
-
-func (j *Job) GetInnerJobsMetadata() []InnerJob {
-	return j.Raw.Jobs
-}
-
-func (j *Job) GetUpstreamJobs() ([]*Job, error) {
-	jobs := make([]*Job, len(j.Raw.UpstreamProjects))
-	for i, job := range j.Raw.UpstreamProjects {
-		ji, err := j.Jenkins.GetJob(job.Name)
-		if err != nil {
-			return nil, err
-		}
-		jobs[i] = ji
-	}
-	return jobs, nil
-}
-
-func (j *Job) GetDownstreamJobs() ([]*Job, error) {
-	jobs := make([]*Job, len(j.Raw.DownstreamProjects))
-	for i, job := range j.Raw.DownstreamProjects {
-		ji, err := j.Jenkins.GetJob(job.Name)
-		if err != nil {
-			return nil, err
-		}
-		jobs[i] = ji
-	}
-	return jobs, nil
-}
-
-func (j *Job) GetInnerJob(id string) (*Job, error) {
-	job := Job{Jenkins: j.Jenkins, Raw: new(JobResponse), Base: j.Base + "/job/" + id}
-	status, err := job.Poll()
-	if err != nil {
-		return nil, err
-	}
-	if status == 200 {
-		return &job, nil
-	}
-	return nil, errors.New(strconv.Itoa(status))
-}
-
-func (j *Job) GetInnerJobs() ([]*Job, error) {
-	jobs := make([]*Job, len(j.Raw.Jobs))
-	for i, job := range j.Raw.Jobs {
-		ji, err := j.GetInnerJob(job.Name)
-		if err != nil {
-			return nil, err
-		}
-		jobs[i] = ji
-	}
-	return jobs, nil
-}
-
-func (j *Job) Enable() (bool, error) {
-	resp, err := j.Jenkins.Requester.Post(j.Base+"/enable", nil, nil, nil)
-	if err != nil {
-		return false, err
-	}
-	if resp.StatusCode != 200 {
-		return false, errors.New(strconv.Itoa(resp.StatusCode))
-	}
-	return true, nil
-}
-
-func (j *Job) Disable() (bool, error) {
-	resp, err := j.Jenkins.Requester.Post(j.Base+"/disable", nil, nil, nil)
-	if err != nil {
-		return false, err
-	}
-	if resp.StatusCode != 200 {
-		return false, errors.New(strconv.Itoa(resp.StatusCode))
-	}
-	return true, nil
-}
-
 func (j *Job) Delete() (bool, error) {
 	resp, err := j.Jenkins.Requester.Post(j.Base+"/doDelete", nil, nil, nil)
 	if err != nil {
@@ -387,13 +305,6 @@ func (j *Job) GetParameters() ([]ParameterDefinition, error) {
 	return parameters, nil
 }
 
-func (j *Job) IsQueued() (bool, error) {
-	if _, err := j.Poll(); err != nil {
-		return false, err
-	}
-	return j.Raw.InQueue, nil
-}
-
 func (j *Job) IsRunning() (bool, error) {
 	if _, err := j.Poll(); err != nil {
 		return false, err
diff --git a/pkg/client/devops/jenkins/pipeline.go b/pkg/client/devops/jenkins/pipeline.go
index 1e162fc..b742bbc 100644
--- a/pkg/client/devops/jenkins/pipeline.go
+++ b/pkg/client/devops/jenkins/pipeline.go
@@ -82,8 +82,6 @@ const (
 
 	CheckPipelienCronUrl = "/job/%s/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?%s"
 	CheckCronUrl         = "/job/%s/descriptorByName/hudson.triggers.TimerTrigger/checkSpec?%s"
-	ToJenkinsfileUrl     = "/pipeline-model-converter/toJenkinsfile"
-	ToJsonUrl            = "/pipeline-model-converter/toJson"
 
 	cronJobLayout = "Monday, January 2, 2006 15:04:05 PM"
 )
diff --git a/pkg/client/devops/jenkins/pipeline_model_converter.go b/pkg/client/devops/jenkins/pipeline_model_converter.go
index 46640a6..bbacc0c 100644
--- a/pkg/client/devops/jenkins/pipeline_model_converter.go
+++ b/pkg/client/devops/jenkins/pipeline_model_converter.go
@@ -34,41 +34,6 @@ type ValidatePipelineJsonResponse struct {
 	}
 }
 
-type PipelineJsonToJenkinsfileResponse struct {
-	Status string `json:"status"`
-	Data   struct {
-		Result      string                   `json:"result"`
-		Errors      []map[string]interface{} `json:"errors"`
-		Jenkinsfile string                   `json:"jenkinsfile"`
-	} `json:"data"`
-}
-
-type JenkinsfileToPipelineJsonResponse struct {
-	Status string `json:"status"`
-	Data   struct {
-		Result string                   `json:"result"`
-		Errors []map[string]interface{} `json:"errors"`
-		Json   map[string]interface{}   `json:"json"`
-	} `json:"data"`
-}
-type StepJsonToJenkinsfileResponse struct {
-	Status string `json:"status"`
-	Data   struct {
-		Result      string                   `json:"result"`
-		Errors      []map[string]interface{} `json:"errors"`
-		Jenkinsfile string                   `json:"jenkinsfile"`
-	} `json:"data"`
-}
-
-type StepsJenkinsfileToJsonResponse struct {
-	Status string `json:"status"`
-	Data   struct {
-		Result string                   `json:"result"`
-		Errors []map[string]interface{} `json:"errors"`
-		Json   []map[string]interface{} `json:"json"`
-	} `json:"data"`
-}
-
 func (j *Jenkins) ValidateJenkinsfile(jenkinsfile string) (*ValidateJenkinsfileResponse, error) {
 	responseStrut := &ValidateJenkinsfileResponse{}
 	query := map[string]string{
@@ -100,63 +65,3 @@ func (j *Jenkins) ValidatePipelineJson(json string) (*ValidatePipelineJsonRespon
 	}
 	return responseStruct, nil
 }
-
-func (j *Jenkins) PipelineJsonToJenkinsfile(json string) (*PipelineJsonToJenkinsfileResponse, error) {
-	responseStrut := &PipelineJsonToJenkinsfileResponse{}
-	query := map[string]string{
-		"json": json,
-	}
-	response, err := j.Requester.PostForm("/pipeline-model-converter/toJenkinsfile", nil, responseStrut, query)
-	if err != nil {
-		return nil, err
-	}
-	if response.StatusCode != http.StatusOK {
-		return nil, errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return responseStrut, nil
-}
-
-func (j *Jenkins) JenkinsfileToPipelineJson(jenkinsfile string) (*JenkinsfileToPipelineJsonResponse, error) {
-	responseStrut := &JenkinsfileToPipelineJsonResponse{}
-	query := map[string]string{
-		"jenkinsfile": jenkinsfile,
-	}
-	response, err := j.Requester.PostForm("/pipeline-model-converter/toJson", nil, responseStrut, query)
-	if err != nil {
-		return nil, err
-	}
-	if response.StatusCode != http.StatusOK {
-		return nil, errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return responseStrut, nil
-}
-
-func (j *Jenkins) StepsJsonToJenkinsfile(json string) (*StepJsonToJenkinsfileResponse, error) {
-	responseStrut := &StepJsonToJenkinsfileResponse{}
-	query := map[string]string{
-		"json": json,
-	}
-	response, err := j.Requester.PostForm("/pipeline-model-converter/stepsToJenkinsfile", nil, responseStrut, query)
-	if err != nil {
-		return nil, err
-	}
-	if response.StatusCode != http.StatusOK {
-		return nil, errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return responseStrut, nil
-}
-
-func (j *Jenkins) StepsJenkinsfileToJson(jenkinsfile string) (*StepsJenkinsfileToJsonResponse, error) {
-	responseStrut := &StepsJenkinsfileToJsonResponse{}
-	query := map[string]string{
-		"jenkinsfile": jenkinsfile,
-	}
-	response, err := j.Requester.PostForm("/pipeline-model-converter/stepsToJson", nil, responseStrut, query)
-	if err != nil {
-		return nil, err
-	}
-	if response.StatusCode != http.StatusOK {
-		return nil, errors.New(strconv.Itoa(response.StatusCode))
-	}
-	return responseStrut, nil
-}
diff --git a/pkg/client/devops/pipeline.go b/pkg/client/devops/pipeline.go
index f61e49c..5b61123 100644
--- a/pkg/client/devops/pipeline.go
+++ b/pkg/client/devops/pipeline.go
@@ -1175,6 +1175,4 @@ type PipelineOperator interface {
 
 	CheckScriptCompile(projectName, pipelineName string, httpParameters *HttpParameters) (*CheckScript, error)
 	CheckCron(projectName string, httpParameters *HttpParameters) (*CheckCronRes, error)
-	ToJenkinsfile(httpParameters *HttpParameters) (*ResJenkinsfile, error)
-	ToJSON(httpParameters *HttpParameters) (map[string]interface{}, error)
 }
diff --git a/pkg/client/devops/role.go b/pkg/client/devops/role.go
index a4cf4fd..8a4eb5a 100644
--- a/pkg/client/devops/role.go
+++ b/pkg/client/devops/role.go
@@ -16,39 +16,6 @@ limitations under the License.
 
 package devops
 
-// define the id of global permission items
-type GlobalPermissionIds struct {
-	Administer              bool `json:"hudson.model.Hudson.Administer"`
-	GlobalRead              bool `json:"hudson.model.Hudson.Read"`
-	CredentialCreate        bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Create"`
-	CredentialUpdate        bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Update"`
-	CredentialView          bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.View"`
-	CredentialDelete        bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Delete"`
-	CredentialManageDomains bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.ManageDomains"`
-	SlaveCreate             bool `json:"hudson.model.Computer.Create"`
-	SlaveConfigure          bool `json:"hudson.model.Computer.Configure"`
-	SlaveDelete             bool `json:"hudson.model.Computer.Delete"`
-	SlaveBuild              bool `json:"hudson.model.Computer.Build"`
-	SlaveConnect            bool `json:"hudson.model.Computer.Connect"`
-	SlaveDisconnect         bool `json:"hudson.model.Computer.Disconnect"`
-	ItemBuild               bool `json:"hudson.model.Item.Build"`
-	ItemCreate              bool `json:"hudson.model.Item.Create"`
-	ItemRead                bool `json:"hudson.model.Item.Read"`
-	ItemConfigure           bool `json:"hudson.model.Item.Configure"`
-	ItemCancel              bool `json:"hudson.model.Item.Cancel"`
-	ItemMove                bool `json:"hudson.model.Item.Move"`
-	ItemDiscover            bool `json:"hudson.model.Item.Discover"`
-	ItemWorkspace           bool `json:"hudson.model.Item.Workspace"`
-	ItemDelete              bool `json:"hudson.model.Item.Delete"`
-	RunUpdate               bool `json:"hudson.model.Run.Update"`
-	RunDelete               bool `json:"hudson.model.Run.Delete"`
-	ViewCreate              bool `json:"hudson.model.View.Create"`
-	ViewConfigure           bool `json:"hudson.model.View.Configure"`
-	ViewRead                bool `json:"hudson.model.View.Read"`
-	ViewDelete              bool `json:"hudson.model.View.Delete"`
-	SCMTag                  bool `json:"hudson.scm.SCM.Tag"`
-}
-
 // define the id of project permission items
 type ProjectPermissionIds struct {
 	CredentialCreate        bool `json:"com.cloudbees.plugins.credentials.CredentialsProvider.Create"`
diff --git a/pkg/client/devops/util/credential.go b/pkg/client/devops/util/credential.go
new file mode 100644
index 0000000..0d67a00
--- /dev/null
+++ b/pkg/client/devops/util/credential.go
@@ -0,0 +1,53 @@
+/*
+Copyright 2022 The KubeSphere Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package util
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/emicklei/go-restful"
+	jcredential "github.com/jenkins-zh/jenkins-client/pkg/credential"
+	v1 "k8s.io/api/core/v1"
+	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
+)
+
+// ConvertSecretToCredential converts a secret to Jenkins credential type
+func ConvertSecretToCredential(secret *v1.Secret) (interface{}, error) {
+	name := secret.GetName()
+
+	switch secret.Type {
+	case devopsv1alpha3.SecretTypeBasicAuth:
+		username := string(secret.Data[devopsv1alpha3.BasicAuthUsernameKey])
+		password := string(secret.Data[devopsv1alpha3.BasicAuthPasswordKey])
+		return jcredential.NewUsernamePasswordCredential(name, username, password), nil
+	case devopsv1alpha3.SecretTypeSSHAuth:
+		username := string(secret.Data[devopsv1alpha3.SSHAuthUsernameKey])
+		passphrase := string(secret.Data[devopsv1alpha3.SSHAuthPassphraseKey])
+		privatekey := string(secret.Data[devopsv1alpha3.SSHAuthPrivateKey])
+		return jcredential.NewSSHCredential(name, username, passphrase, privatekey), nil
+	case devopsv1alpha3.SecretTypeSecretText:
+		secretContent := string(secret.Data[devopsv1alpha3.SecretTextSecretKey])
+		return jcredential.NewSecretTextCredential(name, secretContent), nil
+	case devopsv1alpha3.SecretTypeKubeConfig:
+		secretContent := string(secret.Data[devopsv1alpha3.KubeConfigSecretKey])
+		return jcredential.NewKubeConfigCredential(name, secretContent), nil
+	default:
+		err := fmt.Errorf("error unsupport credential type")
+		return nil, restful.NewError(http.StatusBadRequest, err.Error())
+	}
+}
diff --git a/pkg/kapis/devops/v1alpha2/devops.go b/pkg/kapis/devops/v1alpha2/devops.go
index 067c75e..0dc9d43 100644
--- a/pkg/kapis/devops/v1alpha2/devops.go
+++ b/pkg/kapis/devops/v1alpha2/devops.go
@@ -20,10 +20,11 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"k8s.io/klog"
 	"net/http"
 	"strings"
 
+	"k8s.io/klog"
+
 	"kubesphere.io/devops/pkg/kapis"
 
 	"kubesphere.io/devops/pkg/apiserver/query"
@@ -863,26 +864,6 @@ func (h *ProjectPipelineHandler) CheckCron(req *restful.Request, resp *restful.R
 	resp.WriteAsJson(res)
 }
 
-func (h *ProjectPipelineHandler) ToJenkinsfile(req *restful.Request, resp *restful.Response) {
-	res, err := h.devopsOperator.ToJenkinsfile(req.Request)
-	if err != nil {
-		parseErr(err, resp)
-		return
-	}
-	resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON)
-	resp.WriteAsJson(res)
-}
-
-func (h *ProjectPipelineHandler) ToJSON(req *restful.Request, resp *restful.Response) {
-	res, err := h.devopsOperator.ToJSON(req.Request)
-	if err != nil {
-		parseErr(err, resp)
-		return
-	}
-	resp.Header().Set(restful.HEADER_ContentType, restful.MIME_JSON)
-	resp.WriteAsJson(res)
-}
-
 func (h *ProjectPipelineHandler) GetProjectCredentialUsage(req *restful.Request, resp *restful.Response) {
 	projectId := req.PathParameter("devops")
 	credentialId := req.PathParameter("credential")
diff --git a/pkg/kapis/devops/v1alpha2/register.go b/pkg/kapis/devops/v1alpha2/register.go
index 8a8dec9..aa07a38 100644
--- a/pkg/kapis/devops/v1alpha2/register.go
+++ b/pkg/kapis/devops/v1alpha2/register.go
@@ -631,35 +631,6 @@ func AddPipelineToWebService(webservice *restful.WebService, devopsClient devops
 			Reads(devops.CronData{}).
 			Returns(http.StatusOK, api.StatusOK, devops.CheckCronRes{}).
 			Writes(devops.CheckCronRes{}))
-
-		// match /pipeline-model-converter/toJenkinsfile
-		webservice.Route(webservice.POST("/tojenkinsfile").
-			To(projectPipelineHandler.ToJenkinsfile).
-			Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsJenkinsfileTag}).
-			Consumes("application/x-www-form-urlencoded").
-			Produces("application/json", "charset=utf-8").
-			Doc("Convert json to jenkinsfile format.").
-			Reads(devops.ReqJson{}).
-			Returns(http.StatusOK, api.StatusOK, devops.ResJenkinsfile{}).
-			Writes(devops.ResJenkinsfile{}))
-
-		// match /pipeline-model-converter/toJson
-		/*
-		 * Considering the following reasons, we use a generic data struct here.
-		 * - A fixed go struct might need to change again once Jenkins has new features.
-		 * - No refer requirement for the specific data struct
-		 * Please read the official document if you want to know more details
-		 * https://github.com/jenkinsci/pipeline-model-definition-plugin/blob/fc8d22192d7d3a17badc3b8af7191a84bb7fd4ca/EXTENDING.md#conversion-to-json-representation-from-jenkinsfile
-		 */
-		webservice.Route(webservice.POST("/tojson").
-			To(projectPipelineHandler.ToJSON).
-			Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsJenkinsfileTag}).
-			Consumes("application/x-www-form-urlencoded").
-			Produces("application/json", "charset=utf-8").
-			Doc("Convert jenkinsfile to json format. Usually the frontend uses json to show or edit pipeline").
-			Reads(devops.ReqJenkinsfile{}).
-			Returns(http.StatusOK, api.StatusOK, map[string]interface{}{}).
-			Writes(map[string]interface{}{}))
 	}
 	return nil
 }
diff --git a/pkg/models/devops/common.go b/pkg/models/devops/common.go
index 3ea40fa..b8f73c5 100644
--- a/pkg/models/devops/common.go
+++ b/pkg/models/devops/common.go
@@ -18,8 +18,6 @@ package devops
 
 import (
 	"time"
-
-	"kubesphere.io/devops/pkg/client/devops"
 )
 
 const (
@@ -37,244 +35,6 @@ const (
 	StatusTimeColumn = "status_time"
 )
 
-const (
-	VisibilityPrivate = "private"
-	VisibilityPublic  = "public"
-)
-
-const (
-	KS_ADMIN = "admin"
-)
-
-// define roles of DevOps
-const (
-	ProjectOwner      = "owner"
-	ProjectMaintainer = "maintainer"
-	ProjectDeveloper  = "developer"
-	ProjectReporter   = "reporter"
-)
-
-const (
-	JenkinsAllUserRoleName = "kubesphere-user"
-	JenkinsAdminRoleName   = "admin"
-)
-
-type Role struct {
-	Name        string `json:"name" description:"role's name e.g. owner'"`
-	Description string `json:"description" description:"role 's description'"`
-}
-
-var DefaultRoles = []*Role{
-	{
-		Name:        ProjectOwner,
-		Description: "Owner have access to do all the operations of a DevOps project and own the highest permissions as well.",
-	},
-	{
-		Name:        ProjectMaintainer,
-		Description: "Maintainer have access to manage pipeline and credential configuration in a DevOps project.",
-	},
-	{
-		Name:        ProjectDeveloper,
-		Description: "Developer is able to view and trigger the pipeline.",
-	},
-	{
-		Name:        ProjectReporter,
-		Description: "Reporter is only allowed to view the status of the pipeline.",
-	},
-}
-
-var AllRoleSlice = []string{ProjectDeveloper, ProjectReporter, ProjectMaintainer, ProjectOwner}
-
-// define the permission matrix of owner
-var JenkinsOwnerProjectPermissionIds = &devops.ProjectPermissionIds{
-	CredentialCreate:        true,
-	CredentialDelete:        true,
-	CredentialManageDomains: true,
-	CredentialUpdate:        true,
-	CredentialView:          true,
-	ItemBuild:               true,
-	ItemCancel:              true,
-	ItemConfigure:           true,
-	ItemCreate:              true,
-	ItemDelete:              true,
-	ItemDiscover:            true,
-	ItemMove:                true,
-	ItemRead:                true,
-	ItemWorkspace:           true,
-	RunDelete:               true,
-	RunReplay:               true,
-	RunUpdate:               true,
-	SCMTag:                  true,
-}
-
-// define the permission matrix of DevOps, including owner, maintainer, developer, reporter
-var JenkinsProjectPermissionMap = map[string]devops.ProjectPermissionIds{
-	ProjectOwner: {
-		CredentialCreate:        true,
-		CredentialDelete:        true,
-		CredentialManageDomains: true,
-		CredentialUpdate:        true,
-		CredentialView:          true,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           true,
-		ItemCreate:              true,
-		ItemDelete:              true,
-		ItemDiscover:            true,
-		ItemMove:                true,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  true,
-	},
-	ProjectMaintainer: {
-		CredentialCreate:        true,
-		CredentialDelete:        true,
-		CredentialManageDomains: true,
-		CredentialUpdate:        true,
-		CredentialView:          true,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           false,
-		ItemCreate:              true,
-		ItemDelete:              false,
-		ItemDiscover:            true,
-		ItemMove:                false,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  true,
-	},
-	ProjectDeveloper: {
-		CredentialCreate:        false,
-		CredentialDelete:        false,
-		CredentialManageDomains: false,
-		CredentialUpdate:        false,
-		CredentialView:          false,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           false,
-		ItemCreate:              false,
-		ItemDelete:              false,
-		ItemDiscover:            true,
-		ItemMove:                false,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  false,
-	},
-	ProjectReporter: {
-		CredentialCreate:        false,
-		CredentialDelete:        false,
-		CredentialManageDomains: false,
-		CredentialUpdate:        false,
-		CredentialView:          false,
-		ItemBuild:               false,
-		ItemCancel:              false,
-		ItemConfigure:           false,
-		ItemCreate:              false,
-		ItemDelete:              false,
-		ItemDiscover:            true,
-		ItemMove:                false,
-		ItemRead:                true,
-		ItemWorkspace:           false,
-		RunDelete:               false,
-		RunReplay:               false,
-		RunUpdate:               false,
-		SCMTag:                  false,
-	},
-}
-
-// define the permission matrix of pipeline, including owner, maintainer, developer, reporter
-var JenkinsPipelinePermissionMap = map[string]devops.ProjectPermissionIds{
-	ProjectOwner: {
-		CredentialCreate:        true,
-		CredentialDelete:        true,
-		CredentialManageDomains: true,
-		CredentialUpdate:        true,
-		CredentialView:          true,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           true,
-		ItemCreate:              true,
-		ItemDelete:              true,
-		ItemDiscover:            true,
-		ItemMove:                true,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  true,
-	},
-	ProjectMaintainer: {
-		CredentialCreate:        true,
-		CredentialDelete:        true,
-		CredentialManageDomains: true,
-		CredentialUpdate:        true,
-		CredentialView:          true,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           true,
-		ItemCreate:              true,
-		ItemDelete:              true,
-		ItemDiscover:            true,
-		ItemMove:                true,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  true,
-	},
-	ProjectDeveloper: {
-		CredentialCreate:        false,
-		CredentialDelete:        false,
-		CredentialManageDomains: false,
-		CredentialUpdate:        false,
-		CredentialView:          false,
-		ItemBuild:               true,
-		ItemCancel:              true,
-		ItemConfigure:           false,
-		ItemCreate:              false,
-		ItemDelete:              false,
-		ItemDiscover:            true,
-		ItemMove:                false,
-		ItemRead:                true,
-		ItemWorkspace:           true,
-		RunDelete:               true,
-		RunReplay:               true,
-		RunUpdate:               true,
-		SCMTag:                  false,
-	},
-	ProjectReporter: {
-		CredentialCreate:        false,
-		CredentialDelete:        false,
-		CredentialManageDomains: false,
-		CredentialUpdate:        false,
-		CredentialView:          false,
-		ItemBuild:               false,
-		ItemCancel:              false,
-		ItemConfigure:           false,
-		ItemCreate:              false,
-		ItemDelete:              false,
-		ItemDiscover:            true,
-		ItemMove:                false,
-		ItemRead:                true,
-		ItemWorkspace:           false,
-		RunDelete:               false,
-		RunReplay:               false,
-		RunUpdate:               false,
-		SCMTag:                  false,
-	},
-}
-
 // GetSyncNowTime returns unified sync current time
 func GetSyncNowTime() string {
 	return time.Now().String()
diff --git a/pkg/models/devops/devops.go b/pkg/models/devops/devops.go
index f5479e4..4fadc55 100644
--- a/pkg/models/devops/devops.go
+++ b/pkg/models/devops/devops.go
@@ -36,7 +36,6 @@ import (
 	"k8s.io/apimachinery/pkg/util/validation/field"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/klog/v2"
-
 	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"kubesphere.io/devops/pkg/utils/secretutil"
@@ -120,9 +119,6 @@ type DevopsOperator interface {
 	CheckScriptCompile(projectName, pipelineName string, req *http.Request) (*devops.CheckScript, error)
 	CheckCron(projectName string, req *http.Request) (*devops.CheckCronRes, error)
 
-	ToJenkinsfile(req *http.Request) (*devops.ResJenkinsfile, error)
-	ToJSON(req *http.Request) (map[string]interface{}, error)
-
 	GetJenkinsAgentLabels() ([]string, error)
 }
 
@@ -979,28 +975,6 @@ func (d devopsOperator) CheckCron(projectName string, req *http.Request) (*devop
 	return res, err
 }
 
-func (d devopsOperator) ToJenkinsfile(req *http.Request) (*devops.ResJenkinsfile, error) {
-
-	res, err := d.devopsClient.ToJenkinsfile(convertToHttpParameters(req))
-	if err != nil {
-		klog.Error(err)
-		return nil, err
-	}
-
-	return res, err
-}
-
-func (d devopsOperator) ToJSON(req *http.Request) (map[string]interface{}, error) {
-
-	res, err := d.devopsClient.ToJSON(convertToHttpParameters(req))
-	if err != nil {
-		klog.Error(err)
-		return nil, err
-	}
-
-	return res, err
-}
-
 func (d devopsOperator) GetJenkinsAgentLabels() (labels []string, err error) {
 	var cm *v1.ConfigMap
 	if cm, err = d.k8sclient.CoreV1().ConfigMaps("kubesphere-devops-system").


Test patch:
diff --git a/pkg/client/devops/fake/fakedevops_test.go b/pkg/client/devops/fake/fakedevops_test.go
new file mode 100644
index 0000000..5982640
--- /dev/null
+++ b/pkg/client/devops/fake/fakedevops_test.go
@@ -0,0 +1,251 @@
+/*
+Copyright 2022 KubeSphere Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	v1 "k8s.io/api/core/v1"
+	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
+)
+
+func TestCredential(t *testing.T) {
+	secret := &v1.Secret{}
+	secret.SetName("secret")
+	secret.SetNamespace("project")
+
+	secret1 := secret.DeepCopy()
+	secret1.SetName("secret1")
+
+	client := NewWithCredentials("project", secret.DeepCopy())
+
+	// find credential by a correct name
+	cre, err := client.GetCredentialInProject("project", "secret")
+	assert.NotNil(t, cre)
+	assert.Nil(t, err)
+
+	// not found
+	cre, err = client.GetCredentialInProject("fake", "fake")
+	assert.NotNil(t, err)
+	assert.Nil(t, cre)
+
+	// create a secert that already exist
+	var id string
+	id, err = client.CreateCredentialInProject("project", secret.DeepCopy())
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// delete an existing
+	id, err = client.DeleteCredentialInProject("project", "secret")
+	assert.Nil(t, err)
+	assert.Equal(t, "", id)
+
+	// delete a non-exsting
+	id, err = client.DeleteCredentialInProject("fake", "fake")
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// create it once it was deleted
+	id, err = client.CreateCredentialInProject("project", secret.DeepCopy())
+	assert.Nil(t, err)
+	assert.Equal(t, secret.DeepCopy().GetName(), id)
+
+	// update
+	id, err = client.UpdateCredentialInProject("project", secret.DeepCopy())
+	assert.Nil(t, err)
+	assert.Equal(t, secret.DeepCopy().GetName(), id)
+
+	// update a non-existing
+	id, err = client.UpdateCredentialInProject("project", secret1.DeepCopy())
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+}
+
+func TestPipeline(t *testing.T) {
+	pip := &devopsv1alpha3.Pipeline{}
+	pip.SetName("pip")
+	pip.SetNamespace("project")
+
+	pip1 := pip.DeepCopy()
+	pip1.SetName("pip1")
+
+	client := NewWithPipelines("project", pip.DeepCopy())
+
+	var id string
+	var err error
+
+	// create a non-exsiting project
+	id, err = client.CreateDevOpsProject("project1")
+	assert.Nil(t, err)
+	assert.Equal(t, "project1", id)
+
+	// create an exsiting project
+	id, err = client.CreateDevOpsProject("project")
+	assert.Nil(t, err)
+	assert.Equal(t, "project", id)
+
+	// delete a non-exsiting project
+	assert.NotNil(t, client.DeleteDevOpsProject("project2"))
+
+	// delete an exsiting project
+	assert.Nil(t, client.DeleteDevOpsProject("project1"))
+
+	// get an exsiting project
+	id, err = client.GetDevOpsProject("project")
+	assert.Nil(t, err)
+	assert.Equal(t, "project", id)
+
+	// get a non-existing project
+	id, err = client.GetDevOpsProject("project4")
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// create an existing pipeline
+	id, err = client.CreateProjectPipeline("project", pip.DeepCopy())
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// create a non-existing pipeline
+	id, err = client.CreateProjectPipeline("project", pip1.DeepCopy())
+	assert.Nil(t, err)
+	assert.Empty(t, id)
+
+	// delete a non-existing pipeline
+	id, err = client.DeleteProjectPipeline("project", "pip2")
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// delete an existing pipeline
+	id, err = client.DeleteProjectPipeline("project", "pip1")
+	assert.Nil(t, err)
+	assert.Empty(t, id)
+
+	// update an existing pipeline
+	id, err = client.UpdateProjectPipeline("project", pip.DeepCopy())
+	assert.Nil(t, err)
+	assert.Empty(t, id)
+
+	// update a non-existing pipeline
+	id, err = client.UpdateProjectPipeline("project", pip1.DeepCopy())
+	assert.NotNil(t, err)
+	assert.Empty(t, id)
+
+	// get an existing pipeline
+	var obj interface{}
+	obj, err = client.GetProjectPipelineConfig("project", "pip")
+	assert.Nil(t, err)
+	assert.NotNil(t, obj)
+
+	// get a non-existing pipeline
+	obj, err = client.GetProjectPipelineConfig("project", "pip3")
+	assert.NotNil(t, err)
+	assert.Nil(t, obj)
+}
+
+func TestNotImplement(t *testing.T) {
+	client := New("fake")
+	assert.NotNil(t, client)
+	client = NewFakeDevops(nil)
+	assert.Nil(t, client.ReloadConfiguration())
+	assert.Nil(t, client.ApplyNewSource("fake"))
+
+	var (
+		o1 interface{}
+		o2 interface{}
+		o3 interface{}
+	)
+
+	o1, o2 = client.GetProjectPipelineBuildByType("", "", "")
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetMultiBranchPipelineBuildByType("", "", "", "")
+	assertNils(t, o1, o2)
+	o1, o2 = client.CheckCron("", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.CheckScriptCompile("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetPipeline("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.ListPipelines(nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetPipelineRun("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.StopPipeline("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.ReplayPipeline("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetArtifacts("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.DownloadArtifact("", "", "", "")
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetRunLog("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2, o3 = client.GetStepLog("", "", "", "", "", nil)
+	assertNils(t, o1, o2, o3)
+	o1, o2 = client.RunPipeline("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.ListPipelineRuns("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.SubmitInputStep("", "", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetBranchPipeline("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetBranchPipelineRun("", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.StopBranchPipeline("", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.ReplayBranchPipeline("", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.RunBranchPipeline("", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetBranchArtifacts("", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetBranchRunLog("", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2, o3 = client.GetBranchStepLog("", "", "", "", "", "", nil)
+	assertNils(t, o1, o2, o3)
+	o1, o2 = client.SubmitBranchInputStep("", "", "", "", "", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetPipelineBranch("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.ScanBranch("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetConsoleLog("", "", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetCrumb(nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetSCMServers("", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetSCMOrg("", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.CreateSCMServers("", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.Validate("", nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GetNotifyCommit(nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GithubWebhook(nil)
+	assertNils(t, o1, o2)
+	o1, o2 = client.GenericWebhook(nil)
+	assertNils(t, o1, o2)
+}
+
+func assertNils(t *testing.T, obj ...interface{}) {
+	for _, item := range obj {
+		assert.Nil(t, item)
+	}
+}
diff --git a/pkg/client/devops/jclient/credential_test.go b/pkg/client/devops/jclient/credential_test.go
new file mode 100644
index 0000000..99fec5c
--- /dev/null
+++ b/pkg/client/devops/jclient/credential_test.go
@@ -0,0 +1,123 @@
+/*
+Copyright 2022 The KubeSphere Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package jclient
+
+import (
+	"fmt"
+	"net/url"
+	"strings"
+	"testing"
+
+	"github.com/golang/mock/gomock"
+	jcredential "github.com/jenkins-zh/jenkins-client/pkg/credential"
+	"github.com/jenkins-zh/jenkins-client/pkg/mock/mhttp"
+	"github.com/jenkins-zh/jenkins-client/pkg/util"
+	"github.com/stretchr/testify/assert"
+	v1 "k8s.io/api/core/v1"
+	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
+	devopsutil "kubesphere.io/devops/pkg/client/devops/util"
+
+	"github.com/jenkins-zh/jenkins-client/pkg/core"
+)
+
+func TestCreateCredential(t *testing.T) {
+	var roundTripper *mhttp.MockRoundTripper
+	ctrl := gomock.NewController(t)
+	roundTripper = mhttp.NewMockRoundTripper(ctrl)
+
+	client := &JenkinsClient{
+		Core: core.JenkinsCore{
+			URL:          "http://localhost",
+			RoundTripper: roundTripper,
+		},
+	}
+
+	const folder = "fake"
+	const id = "id"
+	jcredential.PrepareForDeleteCredentialInFolder(roundTripper, "http://localhost", "", "", folder, id)
+	val, err := client.DeleteCredentialInProject(folder, id)
+	assert.Nil(t, err)
+	assert.Equal(t, id, val)
+}
+
+func TestUpdateCredentialInProject(t *testing.T) {
+	var roundTripper *mhttp.MockRoundTripper
+	ctrl := gomock.NewController(t)
+	roundTripper = mhttp.NewMockRoundTripper(ctrl)
+
+	client := &JenkinsClient{
+		Core: core.JenkinsCore{
+			URL:          "http://localhost",
+			RoundTripper: roundTripper,
+		},
+	}
+
+	secret := &v1.Secret{}
+	secret.SetName("id")
+
+	formData := url.Values{}
+	formData.Add("json", fmt.Sprintf(`{"credentials": %s}`, util.TOJSON(secret.DeepCopy())))
+
+	const folder = "fake"
+	const id = "id"
+	jcredential.PrepareForUpdateCredentialInFolder(roundTripper, "http://localhost", "", "",
+		folder, id, strings.NewReader(formData.Encode()))
+	val, err := client.UpdateCredentialInProject(folder, secret.DeepCopy())
+	assert.Nil(t, err)
+	assert.Empty(t, val)
+}
+
+func TestCreateCredentialInProject(t *testing.T) {
+	var roundTripper *mhttp.MockRoundTripper
+	ctrl := gomock.NewController(t)
+	roundTripper = mhttp.NewMockRoundTripper(ctrl)
+
+	client := &JenkinsClient{
+		Core: core.JenkinsCore{
+			URL:          "http://localhost",
+			RoundTripper: roundTripper,
+		},
+	}
+
+	secret := &v1.Secret{}
+	secret.SetName("id")
+	secret.Type = devopsv1alpha3.SecretTypeBasicAuth
+	secret.Data = map[string][]byte{
+		devopsv1alpha3.BasicAuthUsernameKey: []byte("username"),
+		devopsv1alpha3.BasicAuthPasswordKey: []byte("password"),
+	}
+
+	unknownSecret := secret.DeepCopy()
+	unknownSecret.Type = "fake"
+
+	data, err := devopsutil.ConvertSecretToCredential(secret.DeepCopy())
+	assert.Nil(t, err)
+
+	formData := url.Values{}
+	formData.Add("json", fmt.Sprintf(`{"credentials": %s}`, util.TOJSON(data)))
+
+	const folder = "fake"
+	jcredential.PrepareForCreateCredentialInFolder(roundTripper, "http://localhost", "", "",
+		folder, strings.NewReader(formData.Encode()))
+	val, err := client.CreateCredentialInProject(folder, secret.DeepCopy())
+	assert.Nil(t, err)
+	assert.Empty(t, val)
+
+	// create with an unknown secret
+	_, err = client.CreateCredentialInProject(folder, unknownSecret.DeepCopy())
+	assert.NotNil(t, err)
+}
diff --git a/pkg/client/devops/jenkins/credential_test.go b/pkg/client/devops/jenkins/credential_test.go
deleted file mode 100644
index 6fd469b..0000000
--- a/pkg/client/devops/jenkins/credential_test.go
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-Copyright 2020 KubeSphere Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package jenkins
-
-import (
-	"testing"
-
-	v1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func TestNewUsernamePasswordCredential(t *testing.T) {
-	username := "test-user"
-	password := "password"
-	name := "test-secret"
-	secret := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: "test",
-		},
-		Data: map[string][]byte{
-			"username": []byte(username),
-			"password": []byte(password),
-		},
-		Type: "credential.devops.kubesphere.io/basic-auth",
-	}
-	credential := NewUsernamePasswordCredential(secret)
-	if credential.StaplerClass != "com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl" {
-		t.Fatalf("credential's stapler class should be com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl"+
-			"other than %s ", credential.StaplerClass)
-	}
-	if credential.Id != name {
-		t.Fatalf("credential's id should be %s "+
-			"other than %s ", name, credential.Id)
-	}
-	if credential.Username != username {
-		t.Fatalf("credential's username should be %s "+
-			"other than %s ", username, credential.Username)
-	}
-	if credential.Password != password {
-		t.Fatalf("credential's password should be %s "+
-			"other than %s ", password, credential.Password)
-	}
-}
-
-func TestNewSshCredential(t *testing.T) {
-	username := "test-user"
-	passphrase := "passphrase"
-	privatekey := "pk"
-	name := "test-secret"
-	secret := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: "test",
-		},
-		Data: map[string][]byte{
-			"username":    []byte(username),
-			"passphrase":  []byte(passphrase),
-			"private_key": []byte(privatekey),
-		},
-		Type: "credential.devops.kubesphere.io/ssh-auth",
-	}
-	credential := NewSshCredential(secret)
-	if credential.StaplerClass != "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey" {
-		t.Fatalf("credential's stapler class should be com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"+
-			"other than %s ", credential.StaplerClass)
-	}
-	if credential.Id != name {
-		t.Fatalf("credential's id should be %s "+
-			"other than %s ", name, credential.Id)
-	}
-	if credential.Username != username {
-		t.Fatalf("credential's username should be %s "+
-			"other than %s ", username, credential.Username)
-	}
-	if credential.Passphrase != passphrase {
-		t.Fatalf("credential's passphrase should be %s "+
-			"other than %s ", passphrase, credential.Passphrase)
-	}
-	if credential.KeySource.PrivateKey != privatekey {
-		t.Fatalf("credential's privatekey should be %s "+
-			"other than %s ", privatekey, credential.KeySource.PrivateKey)
-	}
-}
-
-func TestNewKubeconfigCredential(t *testing.T) {
-	content := []byte("test-content")
-	name := "test-secret"
-	secret := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: "test",
-		},
-		Type: "credential.devops.kubesphere.io/kubeconfig",
-		Data: map[string][]byte{"content": content},
-	}
-	credential := NewKubeconfigCredential(secret)
-	if credential.StaplerClass != "com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials" {
-		t.Fatalf("credential's stapler class should be com.microsoft.jenkins.kubernetes.credentials.KubeconfigCredentials"+
-			"other than %s ", credential.StaplerClass)
-	}
-	if credential.Id != name {
-		t.Fatalf("credential's id should be %s "+
-			"other than %s ", name, credential.Id)
-	}
-	if credential.KubeconfigSource.Content != string(content) {
-		t.Fatalf("credential's content should be %s "+
-			"other than %s ", string(content), credential.KubeconfigSource.Content)
-	}
-}
-
-func TestNewSecretTextCredential(t *testing.T) {
-	content := []byte("test-content")
-	name := "test-secret"
-	secret := &v1.Secret{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: "test",
-		},
-		Type: "credential.devops.kubesphere.io/secret-text",
-		Data: map[string][]byte{"secret": content},
-	}
-	credential := NewSecretTextCredential(secret)
-	if credential.StaplerClass != "org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl" {
-		t.Fatalf("credential's stapler class should be org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl"+
-			"other than %s ", credential.StaplerClass)
-	}
-	if credential.Id != name {
-		t.Fatalf("credential's id should be %s "+
-			"other than %s ", name, credential.Id)
-	}
-	if credential.Secret != string(content) {
-		t.Fatalf("credential's content should be %s "+
-			"other than %s ", string(content), credential.Secret)
-	}
-}