Repository: kubesphere/ks-devops
Pull request #459 (2022-02-08 07:21:51)

Re-orgnize the controllers package
<!-- 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

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
/kind chore

### What this PR does / why we need it:
It can help contributors to understand all the controllers.

### 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 #

### 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.
-->
I deleted an useless CRD: `fake`

### 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 **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/459#" 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:

- ~~[OWNERS](https://github.com/kubesphere/ks-devops/blob/master/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/459?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) Report
> Merging [#459](https://codecov.io/gh/kubesphere/ks-devops/pull/459?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (3ad865d) into [master](https://codecov.io/gh/kubesphere/ks-devops/commit/d864650606c8e6c781e1a96b1219fbf07b063a97?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (d864650) will **decrease** coverage by `0.00%`.
> The diff coverage is `92.85%`.

[![Impacted file tree graph](https://codecov.io/gh/kubesphere/ks-devops/pull/459/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/459?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere)

```diff
@@            Coverage Diff             @@
##           master     #459      +/-   ##
==========================================
- Coverage   76.92%   76.91%   -0.01%     
==========================================
  Files         119      119              
  Lines       22231    22226       -5     
==========================================
- Hits        17101    17096       -5     
- Misses       4949     4951       +2     
+ Partials      181      179       -2     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `76.91% <92.85%> (-0.01%)` | :arrow_down: |

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/459?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) | Coverage Δ | |
|---|---|---|
| [.../jenkins/devopsproject/devopsproject\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvamVua2lucy9kZXZvcHNwcm9qZWN0L2Rldm9wc3Byb2plY3RfY29udHJvbGxlci5nbw==) | `43.22% <66.66%> (ø)` | |
| [cmd/controller/app/options/feature.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y21kL2NvbnRyb2xsZXIvYXBwL29wdGlvbnMvZmVhdHVyZS5nbw==) | `57.89% <100.00%> (-4.02%)` | :arrow_down: |
| [...ns/devopscredential/devopscredential\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvamVua2lucy9kZXZvcHNjcmVkZW50aWFsL2Rldm9wc2NyZWRlbnRpYWxfY29udHJvbGxlci5nbw==) | `33.33% <100.00%> (ø)` | |
| [...ontrollers/jenkins/pipeline/pipeline\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y29udHJvbGxlcnMvamVua2lucy9waXBlbGluZS9waXBlbGluZV9jb250cm9sbGVyLmdv) | `43.18% <100.00%> (ø)` | |
| [pkg/api/devops/v1alpha3/register.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2FwaS9kZXZvcHMvdjFhbHBoYTMvcmVnaXN0ZXIuZ28=) | `100.00% <100.00%> (ø)` | |
| [pkg/client/git/client.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9naXQvY2xpZW50Lmdv) | `100.00% <0.00%> (ø)` | |
| [pkg/client/git/message.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2NsaWVudC9naXQvbWVzc2FnZS5nbw==) | `100.00% <0.00%> (ø)` | |
| [pkg/kapis/doc/registry.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2thcGlzL2RvYy9yZWdpc3RyeS5nbw==) | `100.00% <0.00%> (ø)` | |
| [cmd/tools/jwt/app/jwt\_root.go](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-Y21kL3Rvb2xzL2p3dC9hcHAvand0X3Jvb3QuZ28=) | `100.00% <0.00%> (ø)` | |
| ... and [36 more](https://codecov.io/gh/kubesphere/ks-devops/pull/459/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/459?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/459?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Last update [d864650...3ad865d](https://codecov.io/gh/kubesphere/ks-devops/pull/459?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: /cc @kubesphere/sig-devops 
ks-ci-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/459#pullrequestreview-878247239" title="LGTM">JohnNiang</a>*, *<a href="https://github.com/kubesphere/ks-devops/pull/459#" 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:

- ~~[OWNERS](https://github.com/kubesphere/ks-devops/blob/master/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":[]} -->

Patch:
diff --git a/PROJECT b/PROJECT
index 8fb7af4..d020631 100644
--- a/PROJECT
+++ b/PROJECT
@@ -4,9 +4,6 @@ resources:
 - group: devops
   kind: Pipeline
   version: v1alpha3
-- group: devops
-  kind: Fake
-  version: v1alpha3
 - group: devops
   kind: PipelineRun
   version: v1alpha3
diff --git a/cmd/controller/app/controllers.go b/cmd/controller/app/controllers.go
index 1850217..3f7f49b 100644
--- a/cmd/controller/app/controllers.go
+++ b/cmd/controller/app/controllers.go
@@ -19,18 +19,17 @@ package app
 import (
 	"kubesphere.io/devops/controllers/addon"
 	"kubesphere.io/devops/controllers/gitrepository"
+	"kubesphere.io/devops/controllers/jenkins/devopscredential"
+	"kubesphere.io/devops/controllers/jenkins/devopsproject"
 	"kubesphere.io/devops/pkg/jwt/token"
 	"kubesphere.io/devops/pkg/server/errors"
 
 	"github.com/jenkins-zh/jenkins-client/pkg/core"
 	"k8s.io/klog"
 	"kubesphere.io/devops/cmd/controller/app/options"
-	"kubesphere.io/devops/controllers/devopscredential"
-	"kubesphere.io/devops/controllers/devopsproject"
 	"kubesphere.io/devops/controllers/jenkins/config"
 	jenkinspipeline "kubesphere.io/devops/controllers/jenkins/pipeline"
 	"kubesphere.io/devops/controllers/jenkins/pipelinerun"
-	"kubesphere.io/devops/controllers/pipeline"
 	"kubesphere.io/devops/controllers/s2ibinary"
 	"kubesphere.io/devops/controllers/s2irun"
 	"kubesphere.io/devops/pkg/client/devops"
@@ -114,17 +113,24 @@ func addControllers(mgr manager.Manager, client k8s.Client, informerFactory info
 				ReloadCasCDelay: s.JenkinsOptions.ReloadCasCDelay,
 			}, s.JenkinsOptions))
 		},
-		"devopscredential": func(mgr manager.Manager) error {
-			return mgr.Add(devopscredential.NewController(client.Kubernetes(),
+		"jenkins": func(mgr manager.Manager) error {
+			err := mgr.Add(devopscredential.NewController(client.Kubernetes(),
 				devopsClient,
 				informerFactory.KubernetesSharedInformerFactory().Core().V1().Namespaces(),
 				informerFactory.KubernetesSharedInformerFactory().Core().V1().Secrets()))
-		},
-		"devopsprojects": func(mgr manager.Manager) error {
-			return mgr.Add(devopsproject.NewController(client.Kubernetes(),
-				client.KubeSphere(), devopsClient,
-				informerFactory.KubernetesSharedInformerFactory().Core().V1().Namespaces(),
-				informerFactory.KubeSphereSharedInformerFactory().Devops().V1alpha3().DevOpsProjects()))
+			if err == nil {
+				err = mgr.Add(devopsproject.NewController(client.Kubernetes(),
+					client.KubeSphere(), devopsClient,
+					informerFactory.KubernetesSharedInformerFactory().Core().V1().Namespaces(),
+					informerFactory.KubeSphereSharedInformerFactory().Devops().V1alpha3().DevOpsProjects()))
+			}
+			if err == nil {
+				err = mgr.Add(jenkinspipeline.NewController(client.Kubernetes(),
+					client.KubeSphere(), devopsClient,
+					informerFactory.KubernetesSharedInformerFactory().Core().V1().Namespaces(),
+					informerFactory.KubeSphereSharedInformerFactory().Devops().V1alpha3().Pipelines()))
+			}
+			return err
 		},
 		"s2ibinary": func(mgr manager.Manager) error {
 			return mgr.Add(s2ibinary.NewController(client.Kubernetes(),
@@ -139,12 +145,6 @@ func addControllers(mgr manager.Manager, client k8s.Client, informerFactory info
 				kubesphereInformer.Devops().V1alpha1().S2iBinaries(),
 				kubesphereInformer.Devops().V1alpha1().S2iRuns()))
 		},
-		"pipeline": func(mgr manager.Manager) error {
-			return mgr.Add(pipeline.NewController(client.Kubernetes(),
-				client.KubeSphere(), devopsClient,
-				informerFactory.KubernetesSharedInformerFactory().Core().V1().Namespaces(),
-				informerFactory.KubeSphereSharedInformerFactory().Devops().V1alpha3().Pipelines()))
-		},
 	}
 
 	// Add all controllers into manager.
diff --git a/cmd/controller/app/options/feature.go b/cmd/controller/app/options/feature.go
index 8e1ebf8..18eab4b 100644
--- a/cmd/controller/app/options/feature.go
+++ b/cmd/controller/app/options/feature.go
@@ -33,12 +33,10 @@ type FeatureOptions struct {
 // it supports a special key 'all', the default config is not working if 'all' is false
 func (o *FeatureOptions) GetControllers() map[string]bool {
 	defaultMap := map[string]bool{
-		"s2ibinary":        true,
-		"s2irun":           true,
-		"pipeline":         true,
-		"devopsprojects":   true,
-		"devopscredential": true,
-		"jenkinsconfig":    true,
+		"s2ibinary":     true,
+		"s2irun":        true,
+		"jenkins":       true,
+		"jenkinsconfig": true,
 	}
 
 	// support to only enable the specific controllers
diff --git a/controllers/README.md b/controllers/README.md
new file mode 100644
index 0000000..9453cea
--- /dev/null
+++ b/controllers/README.md
@@ -0,0 +1,3 @@
+Thanks for your contribution to the controller area.
+
+If you create a new controller, please don't forget to add it to `cmd/controller/app/controllers.go`.
diff --git a/controllers/jenkins/README.md b/controllers/jenkins/README.md
new file mode 100644
index 0000000..2f0bfeb
--- /dev/null
+++ b/controllers/jenkins/README.md
@@ -0,0 +1,1 @@
+All Jenkins-related controllers live here.
diff --git a/controllers/devopscredential/devopscredential_controller.go b/controllers/jenkins/devopscredential/devopscredential_controller.go
similarity index 96%
rename from controllers/devopscredential/devopscredential_controller.go
rename to controllers/jenkins/devopscredential/devopscredential_controller.go
index ca7026a..f9e1dc8 100644
--- a/controllers/devopscredential/devopscredential_controller.go
+++ b/controllers/jenkins/devopscredential/devopscredential_controller.go
@@ -42,7 +42,6 @@ import (
 
 	devopsv1alpha3 "kubesphere.io/devops/pkg/api/devops/v1alpha3"
 
-	kubesphereclient "kubesphere.io/devops/pkg/client/clientset/versioned"
 	devopsClient "kubesphere.io/devops/pkg/client/devops"
 	"kubesphere.io/devops/pkg/constants"
 	"kubesphere.io/devops/pkg/utils"
@@ -54,10 +53,9 @@ import (
   DevOps project controller is used to maintain the state of the DevOps project.
 */
 
+// Controller is the controller for DevOpsProject
 type Controller struct {
 	client           clientset.Interface
-	kubesphereClient kubesphereclient.Interface
-
 	eventBroadcaster record.EventBroadcaster
 	eventRecorder    record.EventRecorder
 
@@ -74,6 +72,7 @@ type Controller struct {
 	devopsClient devopsClient.Interface
 }
 
+// NewController creates an instance of the DevOpsProject controller
 func NewController(client clientset.Interface,
 	devopsClient devopsClient.Interface,
 	namespaceInformer corev1informer.NamespaceInformer,
@@ -181,10 +180,12 @@ func (c *Controller) worker() {
 	}
 }
 
+// Start starts the controller
 func (c *Controller) Start(stopCh <-chan struct{}) error {
 	return c.Run(1, stopCh)
 }
 
+// Run runs the controller
 func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
 	defer utilruntime.HandleCrash()
 	defer c.workqueue.ShutDown()
@@ -249,13 +250,12 @@ func (c *Controller) syncHandler(key string) error {
 		//If the sync is successful, return handle
 		if state, ok := copySecret.Annotations[devopsv1alpha3.CredentialSyncStatusAnnoKey]; ok && state == constants.StatusSuccessful {
 			specHash := utils.ComputeHash(copySecret.Data)
-			oldHash, _ := copySecret.Annotations[devopsv1alpha3.DevOpsCredentialDataHash] // don't need to check if it's nil, only compare if they're different
+			oldHash := copySecret.Annotations[devopsv1alpha3.DevOpsCredentialDataHash] // don't need to check if it's nil, only compare if they're different
 			if specHash == oldHash {
 				// it was synced successfully, and there's any change with the Pipeline spec, skip this round
 				return nil
-			} else {
-				copySecret.Annotations[devopsv1alpha3.DevOpsCredentialDataHash] = specHash
 			}
+			copySecret.Annotations[devopsv1alpha3.DevOpsCredentialDataHash] = specHash
 		}
 
 		// https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers
diff --git a/controllers/devopscredential/devopscredential_controller_test.go b/controllers/jenkins/devopscredential/devopscredential_controller_test.go
similarity index 100%
rename from controllers/devopscredential/devopscredential_controller_test.go
rename to controllers/jenkins/devopscredential/devopscredential_controller_test.go
diff --git a/controllers/devopsproject/devopsproject_controller.go b/controllers/jenkins/devopsproject/devopsproject_controller.go
similarity index 97%
rename from controllers/devopsproject/devopsproject_controller.go
rename to controllers/jenkins/devopsproject/devopsproject_controller.go
index 7bcf2f3..547420f 100644
--- a/controllers/devopsproject/devopsproject_controller.go
+++ b/controllers/jenkins/devopsproject/devopsproject_controller.go
@@ -53,10 +53,7 @@ import (
 	devopslisters "kubesphere.io/devops/pkg/client/listers/devops/v1alpha3"
 )
 
-/**
-  DevOps project controller is used to maintain the state of the DevOps project.
-*/
-
+// Controller is the controller of the DevOpsProject
 type Controller struct {
 	client           clientset.Interface
 	kubesphereClient kubesphereclient.Interface
@@ -70,8 +67,6 @@ type Controller struct {
 	namespaceLister corev1lister.NamespaceLister
 	namespaceSynced cache.InformerSynced
 
-	workspaceSynced cache.InformerSynced
-
 	workqueue workqueue.RateLimitingInterface
 
 	workerLoopPeriod time.Duration
@@ -79,6 +74,7 @@ type Controller struct {
 	devopsClient devopsClient.Interface
 }
 
+// NewController creates the instance of controller
 func NewController(client clientset.Interface,
 	kubesphereClient kubesphereclient.Interface,
 	devopsClinet devopsClient.Interface,
@@ -174,10 +170,12 @@ func (c *Controller) worker() {
 	}
 }
 
+// Start starts the controller
 func (c *Controller) Start(stopCh <-chan struct{}) error {
 	return c.Run(1, stopCh)
 }
 
+// Run runs the controller
 func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
 	defer utilruntime.HandleCrash()
 	defer c.workqueue.ShutDown()
@@ -227,7 +225,7 @@ func (c *Controller) syncHandler(key string) error {
 		if project.Status.AdminNamespace != "" {
 			ns, err := c.namespaceLister.Get(project.Status.AdminNamespace)
 			if err != nil && !errors.IsNotFound(err) {
-				klog.V(8).Info(err, fmt.Sprintf("faild to get namespace"))
+				klog.V(8).Info(err, "failed to get namespace")
 				return err
 			} else if errors.IsNotFound(err) {
 				// if admin ns is not found, clean project status, rerun reconcile
@@ -330,7 +328,7 @@ func (c *Controller) syncHandler(key string) error {
 		}
 		copyProject.Annotations[devopsv1alpha3.DevOpeProjectSyncStatusAnnoKey] = constants.StatusSuccessful
 		if !reflect.DeepEqual(copyProject, project) {
-			copyProject, err = c.kubesphereClient.DevopsV1alpha3().DevOpsProjects().Update(context.Background(), copyProject, metav1.UpdateOptions{})
+			_, err = c.kubesphereClient.DevopsV1alpha3().DevOpsProjects().Update(context.Background(), copyProject, metav1.UpdateOptions{})
 			if err != nil {
 				klog.V(8).Info(err, fmt.Sprintf("failed to update ns %s ", key))
 				return err
@@ -434,6 +432,6 @@ func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject)
 		ns.Annotations = map[string]string{constants.CreatorAnnotationKey: creator}
 	}
 
-	controllerutil.SetControllerReference(project, ns, scheme.Scheme)
+	_ = controllerutil.SetControllerReference(project, ns, scheme.Scheme)
 	return ns
 }
diff --git a/controllers/devopsproject/devopsproject_controller_test.go b/controllers/jenkins/devopsproject/devopsproject_controller_test.go
similarity index 100%
rename from controllers/devopsproject/devopsproject_controller_test.go
rename to controllers/jenkins/devopsproject/devopsproject_controller_test.go
diff --git a/controllers/pipeline/pipeline_controller.go b/controllers/jenkins/pipeline/pipeline_controller.go
similarity index 94%
rename from controllers/pipeline/pipeline_controller.go
rename to controllers/jenkins/pipeline/pipeline_controller.go
index 195f711..ff31aa9 100644
--- a/controllers/pipeline/pipeline_controller.go
+++ b/controllers/jenkins/pipeline/pipeline_controller.go
@@ -24,7 +24,6 @@ import (
 	"time"
 
 	"kubesphere.io/devops/pkg/utils"
-	"kubesphere.io/devops/pkg/utils/k8sutil"
 	"kubesphere.io/devops/pkg/utils/sliceutil"
 
 	"github.com/emicklei/go-restful"
@@ -52,10 +51,7 @@ import (
 	"kubesphere.io/devops/pkg/constants"
 )
 
-/**
-  DevOps project controller is used to maintain the state of the DevOps project.
-*/
-
+// Controller is the controller of the Pipeline
 type Controller struct {
 	client           clientset.Interface
 	kubesphereClient kubesphereclient.Interface
@@ -75,6 +71,7 @@ type Controller struct {
 	devopsClient     devopsClient.Interface
 }
 
+// NewController creates the controller instance
 func NewController(client clientset.Interface,
 	kubesphereClient kubesphereclient.Interface,
 	devopsClient devopsClient.Interface,
@@ -176,10 +173,12 @@ func (c *Controller) worker() {
 	}
 }
 
+// Start starts the controller
 func (c *Controller) Start(stopCh <-chan struct{}) error {
 	return c.Run(1, stopCh)
 }
 
+// Run runs the controller
 func (c *Controller) Run(workers int, stopCh <-chan struct{}) error {
 	defer utilruntime.HandleCrash()
 	defer c.workqueue.ShutDown()
@@ -244,14 +243,13 @@ func (c *Controller) syncHandler(key string) error {
 		//If the sync is successful, return handle
 		if state, ok := copyPipeline.Annotations[devopsv1alpha3.PipelineSyncStatusAnnoKey]; ok && state == constants.StatusSuccessful {
 			specHash := utils.ComputeHash(copyPipeline.Spec)
-			oldHash, _ := copyPipeline.Annotations[devopsv1alpha3.PipelineSpecHash] // don't need to check if it's nil, only compare if they're different
+			oldHash := copyPipeline.Annotations[devopsv1alpha3.PipelineSpecHash] // don't need to check if it's nil, only compare if they're different
 			if specHash == oldHash {
 				klog.V(9).Info(fmt.Sprintf("%s/%s has no changes in spec", copyPipeline.Namespace, copyPipeline.Name))
 				// it was synced successfully, and there's any change with the Pipeline spec, skip this round
 				return nil
-			} else {
-				copyPipeline.Annotations[devopsv1alpha3.PipelineSpecHash] = specHash
 			}
+			copyPipeline.Annotations[devopsv1alpha3.PipelineSpecHash] = specHash
 		}
 
 		// https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers
@@ -322,10 +320,3 @@ func (c *Controller) syncHandler(key string) error {
 	}
 	return nil
 }
-
-func isDevOpsProjectAdminNamespace(namespace *v1.Namespace) bool {
-	_, ok := namespace.Labels[constants.DevOpsProjectLabelKey]
-
-	return ok && k8sutil.IsControlledBy(namespace.OwnerReferences,
-		devopsv1alpha3.ResourceKindDevOpsProject, "")
-}
diff --git a/controllers/pipeline/pipeline_controller_test.go b/controllers/jenkins/pipeline/pipeline_controller_test.go
similarity index 100%
rename from controllers/pipeline/pipeline_controller_test.go
rename to controllers/jenkins/pipeline/pipeline_controller_test.go
diff --git a/pkg/api/devops/v1alpha3/fake_types.go b/pkg/api/devops/v1alpha3/fake_types.go
deleted file mode 100644
index 3b0d027..0000000
--- a/pkg/api/devops/v1alpha3/fake_types.go
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-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 v1alpha3
-
-import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
-
-// FakeSpec defines the desired state of Fake
-type FakeSpec struct {
-	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
-	// Important: Run "make" to regenerate code after modifying this file
-
-	// Foo is an example field of Fake. Edit Fake_types.go to remove/update
-	Foo string `json:"foo,omitempty"`
-}
-
-// FakeStatus defines the observed state of Fake
-type FakeStatus struct {
-	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
-	// Important: Run "make" to regenerate code after modifying this file
-}
-
-// +kubebuilder:object:root=true
-
-// Fake is the Schema for the fakes API
-type Fake struct {
-	metav1.TypeMeta   `json:",inline"`
-	metav1.ObjectMeta `json:"metadata,omitempty"`
-
-	Spec   FakeSpec   `json:"spec,omitempty"`
-	Status FakeStatus `json:"status,omitempty"`
-}
-
-// +kubebuilder:object:root=true
-
-// FakeList contains a list of Fake
-type FakeList struct {
-	metav1.TypeMeta `json:",inline"`
-	metav1.ListMeta `json:"metadata,omitempty"`
-	Items           []Fake `json:"items"`
-}
-
-func init() {
-	SchemeBuilder.Register(&Fake{}, &FakeList{})
-}
diff --git a/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go b/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
index 099faf4..85e22ae 100644
--- a/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
+++ b/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
@@ -187,95 +187,6 @@ func (in *DiscoverPRFromForks) DeepCopy() *DiscoverPRFromForks {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Fake) DeepCopyInto(out *Fake) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
-	out.Status = in.Status
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Fake.
-func (in *Fake) DeepCopy() *Fake {
-	if in == nil {
-		return nil
-	}
-	out := new(Fake)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *Fake) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FakeList) DeepCopyInto(out *FakeList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]Fake, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeList.
-func (in *FakeList) DeepCopy() *FakeList {
-	if in == nil {
-		return nil
-	}
-	out := new(FakeList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *FakeList) DeepCopyObject() runtime.Object {
-	if c := in.DeepCopy(); c != nil {
-		return c
-	}
-	return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FakeSpec) DeepCopyInto(out *FakeSpec) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeSpec.
-func (in *FakeSpec) DeepCopy() *FakeSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(FakeSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FakeStatus) DeepCopyInto(out *FakeStatus) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeStatus.
-func (in *FakeStatus) DeepCopy() *FakeStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(FakeStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *GenericVariable) DeepCopyInto(out *GenericVariable) {
 	*out = *in


Test patch:
diff --git a/cmd/controller/app/options/feature_test.go b/cmd/controller/app/options/feature_test.go
index 77820c5..bd2b8b8 100644
--- a/cmd/controller/app/options/feature_test.go
+++ b/cmd/controller/app/options/feature_test.go
@@ -35,12 +35,10 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
 			Controllers: map[string]bool{},
 		},
 		want: map[string]bool{
-			"s2ibinary":        true,
-			"s2irun":           true,
-			"pipeline":         true,
-			"devopsprojects":   true,
-			"devopscredential": true,
-			"jenkinsconfig":    true,
+			"s2ibinary":     true,
+			"s2irun":        true,
+			"jenkins":       true,
+			"jenkinsconfig": true,
 		},
 	}, {
 		name: "no input (be nil) from users",
@@ -48,12 +46,10 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
 			Controllers: nil,
 		},
 		want: map[string]bool{
-			"s2ibinary":        true,
-			"s2irun":           true,
-			"pipeline":         true,
-			"devopsprojects":   true,
-			"devopscredential": true,
-			"jenkinsconfig":    true,
+			"s2ibinary":     true,
+			"s2irun":        true,
+			"jenkins":       true,
+			"jenkinsconfig": true,
 		},
 	}, {
 		name: "merge with the input from users",
@@ -64,13 +60,11 @@ func TestFeatureOptions_GetControllers(t *testing.T) {
 			},
 		},
 		want: map[string]bool{
-			"s2ibinary":        true,
-			"s2irun":           false,
-			"pipeline":         true,
-			"devopsprojects":   true,
-			"devopscredential": true,
-			"jenkinsconfig":    true,
-			"fake":             true,
+			"s2ibinary":     true,
+			"s2irun":        false,
+			"jenkins":       true,
+			"jenkinsconfig": true,
+			"fake":          true,
 		},
 	}, {
 		name: "only enable the specific controllers",