Repository: kubesphere/ks-devops
Pull request #477 (2022-02-24 15:34:05)

Move templates types to v1alpha3
### What type of PR is this?

/kind api-change

### What this PR does / why we need it:

Move `ClusterTemplate` and `Template` types into `v1alpha3`.

### Which issue(s) this PR fixes:

Fixes #

### Special notes for reviewers:

RESTful APIs related to `ClusterTemplate` and `Template` will be changed by another PR.

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
- [x] Already added the RBAC markers for the new controllers

### Does this PR introduce a user-facing change??

```release-note
None
```


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

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/477#" title="Author self-approved">JohnNiang</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **linuxsuren** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @linuxsuren` in a comment when ready.

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"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/477?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) Report
> Merging [#477](https://codecov.io/gh/kubesphere/ks-devops/pull/477?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (600b03d) into [master](https://codecov.io/gh/kubesphere/ks-devops/commit/7090ba5f4af621bd33eff993017092d1e80b9bc6?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) (7090ba5) will **increase** coverage by `0.02%`.
> The diff coverage is `72.72%`.

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

```diff
@@            Coverage Diff             @@
##           master     #477      +/-   ##
==========================================
+ Coverage   76.94%   76.97%   +0.02%     
==========================================
  Files         132      132              
  Lines       22676    22675       -1     
==========================================
+ Hits        17448    17453       +5     
+ Misses       5038     5033       -5     
+ Partials      190      189       -1     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `76.97% <72.72%> (+0.02%)` | :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/477?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere) | Coverage Δ | |
|---|---|---|
| [pkg/kapis/devops/v1alpha1/template/route.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2thcGlzL2Rldm9wcy92MWFscGhhMS90ZW1wbGF0ZS9yb3V0ZS5nbw==) | `0.00% <0.00%> (ø)` | |
| [pkg/api/devops/v1alpha3/clustertemplate\_types.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2FwaS9kZXZvcHMvdjFhbHBoYTMvY2x1c3RlcnRlbXBsYXRlX3R5cGVzLmdv) | `50.00% <100.00%> (ø)` | |
| [pkg/api/devops/v1alpha3/template\_types.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2FwaS9kZXZvcHMvdjFhbHBoYTMvdGVtcGxhdGVfdHlwZXMuZ28=) | `100.00% <100.00%> (ø)` | |
| [...vops/v1alpha1/template/cluster\_template\_handler.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2thcGlzL2Rldm9wcy92MWFscGhhMS90ZW1wbGF0ZS9jbHVzdGVyX3RlbXBsYXRlX2hhbmRsZXIuZ28=) | `90.90% <100.00%> (ø)` | |
| [pkg/kapis/devops/v1alpha1/template/render.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2thcGlzL2Rldm9wcy92MWFscGhhMS90ZW1wbGF0ZS9yZW5kZXIuZ28=) | `100.00% <100.00%> (ø)` | |
| [...kapis/devops/v1alpha1/template/template\_handler.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere#diff-cGtnL2thcGlzL2Rldm9wcy92MWFscGhhMS90ZW1wbGF0ZS90ZW1wbGF0ZV9oYW5kbGVyLmdv) | `92.85% <100.00%> (ø)` | |
| [...ontrollers/jenkins/pipeline/pipeline\_controller.go](https://codecov.io/gh/kubesphere/ks-devops/pull/477/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% <0.00%> (+3.78%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/kubesphere/ks-devops/pull/477?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/477?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubesphere). Last update [7090ba5...600b03d](https://codecov.io/gh/kubesphere/ks-devops/pull/477?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).

ks-ci-bot: @JohnNiang: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
ks-ci-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubesphere/ks-devops/pull/477#" title="Author self-approved">JohnNiang</a>*, *<a href="https://github.com/kubesphere/ks-devops/pull/477#pullrequestreview-893397914" title="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/config/crd/bases/devops.kubesphere.io_clustertemplates.yaml b/config/crd/bases/devops.kubesphere.io_clustertemplates.yaml
index e9cb20a..36c05a7 100644
--- a/config/crd/bases/devops.kubesphere.io_clustertemplates.yaml
+++ b/config/crd/bases/devops.kubesphere.io_clustertemplates.yaml
@@ -16,7 +16,7 @@ spec:
     singular: clustertemplate
   scope: Cluster
   versions:
-  - name: v1alpha1
+  - name: v1alpha3
     schema:
       openAPIV3Schema:
         description: ClusterTemplate is the Schema for the clustertemplates API
diff --git a/config/crd/bases/devops.kubesphere.io_templates.yaml b/config/crd/bases/devops.kubesphere.io_templates.yaml
index 31825db..05e4500 100644
--- a/config/crd/bases/devops.kubesphere.io_templates.yaml
+++ b/config/crd/bases/devops.kubesphere.io_templates.yaml
@@ -16,7 +16,7 @@ spec:
     singular: template
   scope: Namespaced
   versions:
-  - name: v1alpha1
+  - name: v1alpha3
     schema:
       openAPIV3Schema:
         description: Template is the Schema for the templates API
diff --git a/controllers/template/clustertemplate_controller.go b/controllers/template/clustertemplate_controller.go
index cbc6490..f39bb96 100644
--- a/controllers/template/clustertemplate_controller.go
+++ b/controllers/template/clustertemplate_controller.go
@@ -18,7 +18,7 @@ package template
 
 import (
 	"context"
-	devopsv1alpha1 "kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 
 	"github.com/go-logr/logr"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -57,6 +57,6 @@ func (r *ClusterTemplateReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er
 // SetupWithManager sets up the controller with the Manager.
 func (r *ClusterTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
-		For(&devopsv1alpha1.ClusterTemplate{}).
+		For(&v1alpha3.ClusterTemplate{}).
 		Complete(r)
 }
diff --git a/controllers/template/template_controller.go b/controllers/template/template_controller.go
index df6a9ad..ca7bb48 100644
--- a/controllers/template/template_controller.go
+++ b/controllers/template/template_controller.go
@@ -18,7 +18,7 @@ package template
 
 import (
 	"context"
-	devopsv1alpha1 "kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 
 	"github.com/go-logr/logr"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -57,6 +57,6 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
 // SetupWithManager sets up the controller with the Manager.
 func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
 	return ctrl.NewControllerManagedBy(mgr).
-		For(&devopsv1alpha1.Template{}).
+		For(&v1alpha3.Template{}).
 		Complete(r)
 }
diff --git a/pkg/api/devops/v1alpha1/zz_generated.deepcopy.go b/pkg/api/devops/v1alpha1/zz_generated.deepcopy.go
index 18029b8..77211a3 100644
--- a/pkg/api/devops/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/api/devops/v1alpha1/zz_generated.deepcopy.go
@@ -240,65 +240,6 @@ func (in *CGroupLimits) DeepCopy() *CGroupLimits {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ClusterTemplate) DeepCopyInto(out *ClusterTemplate) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-	out.Status = in.Status
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplate.
-func (in *ClusterTemplate) DeepCopy() *ClusterTemplate {
-	if in == nil {
-		return nil
-	}
-	out := new(ClusterTemplate)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *ClusterTemplate) 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 *ClusterTemplateList) DeepCopyInto(out *ClusterTemplateList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]ClusterTemplate, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplateList.
-func (in *ClusterTemplateList) DeepCopy() *ClusterTemplateList {
-	if in == nil {
-		return nil
-	}
-	out := new(ClusterTemplateList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *ClusterTemplateList) 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 *ContainerConfig) DeepCopyInto(out *ContainerConfig) {
 	*out = *in
@@ -542,21 +483,6 @@ func (in *Parameter) DeepCopy() *Parameter {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ParameterValidation) DeepCopyInto(out *ParameterValidation) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterValidation.
-func (in *ParameterValidation) DeepCopy() *ParameterValidation {
-	if in == nil {
-		return nil
-	}
-	out := new(ParameterValidation)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) {
 	*out = *in
@@ -1145,123 +1071,6 @@ func (in *S2iRunStatus) DeepCopy() *S2iRunStatus {
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Template) DeepCopyInto(out *Template) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	in.Spec.DeepCopyInto(&out.Spec)
-	out.Status = in.Status
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Template.
-func (in *Template) DeepCopy() *Template {
-	if in == nil {
-		return nil
-	}
-	out := new(Template)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *Template) 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 *TemplateList) DeepCopyInto(out *TemplateList) {
-	*out = *in
-	out.TypeMeta = in.TypeMeta
-	in.ListMeta.DeepCopyInto(&out.ListMeta)
-	if in.Items != nil {
-		in, out := &in.Items, &out.Items
-		*out = make([]Template, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateList.
-func (in *TemplateList) DeepCopy() *TemplateList {
-	if in == nil {
-		return nil
-	}
-	out := new(TemplateList)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *TemplateList) 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 *TemplateParameter) DeepCopyInto(out *TemplateParameter) {
-	*out = *in
-	in.Default.DeepCopyInto(&out.Default)
-	if in.Validation != nil {
-		in, out := &in.Validation, &out.Validation
-		*out = new(ParameterValidation)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateParameter.
-func (in *TemplateParameter) DeepCopy() *TemplateParameter {
-	if in == nil {
-		return nil
-	}
-	out := new(TemplateParameter)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TemplateSpec) DeepCopyInto(out *TemplateSpec) {
-	*out = *in
-	if in.Parameters != nil {
-		in, out := &in.Parameters, &out.Parameters
-		*out = make([]TemplateParameter, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateSpec.
-func (in *TemplateSpec) DeepCopy() *TemplateSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(TemplateSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TemplateStatus) DeepCopyInto(out *TemplateStatus) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateStatus.
-func (in *TemplateStatus) DeepCopy() *TemplateStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(TemplateStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *UserDefineTemplate) DeepCopyInto(out *UserDefineTemplate) {
 	*out = *in
diff --git a/pkg/api/devops/v1alpha1/clustertemplate_types.go b/pkg/api/devops/v1alpha3/clustertemplate_types.go
similarity index 98%
rename from pkg/api/devops/v1alpha1/clustertemplate_types.go
rename to pkg/api/devops/v1alpha3/clustertemplate_types.go
index b86ed5b..e0a54af 100644
--- a/pkg/api/devops/v1alpha1/clustertemplate_types.go
+++ b/pkg/api/devops/v1alpha3/clustertemplate_types.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package v1alpha1
+package v1alpha3
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/pkg/api/devops/v1alpha1/template_interface.go b/pkg/api/devops/v1alpha3/template_interface.go
similarity index 98%
rename from pkg/api/devops/v1alpha1/template_interface.go
rename to pkg/api/devops/v1alpha3/template_interface.go
index 0899c9f..e6e06ec 100644
--- a/pkg/api/devops/v1alpha1/template_interface.go
+++ b/pkg/api/devops/v1alpha3/template_interface.go
@@ -13,7 +13,7 @@
 // limitations under the License.
 //
 
-package v1alpha1
+package v1alpha3
 
 import (
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/pkg/api/devops/v1alpha1/template_types.go b/pkg/api/devops/v1alpha3/template_types.go
similarity index 99%
rename from pkg/api/devops/v1alpha1/template_types.go
rename to pkg/api/devops/v1alpha3/template_types.go
index 5aeae97..598ac07 100644
--- a/pkg/api/devops/v1alpha1/template_types.go
+++ b/pkg/api/devops/v1alpha3/template_types.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package v1alpha1
+package v1alpha3
 
 import (
 	apiextensionv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
diff --git a/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go b/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
index 6068911..275e380 100644
--- a/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
+++ b/pkg/api/devops/v1alpha3/zz_generated.deepcopy.go
@@ -24,7 +24,7 @@ package v1alpha3
 import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
-	runtime "k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime"
 )
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@@ -140,6 +140,65 @@ func (in *BitbucketServerSource) DeepCopy() *BitbucketServerSource {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ClusterTemplate) DeepCopyInto(out *ClusterTemplate) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplate.
+func (in *ClusterTemplate) DeepCopy() *ClusterTemplate {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterTemplate)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterTemplate) 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 *ClusterTemplateList) DeepCopyInto(out *ClusterTemplateList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]ClusterTemplate, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTemplateList.
+func (in *ClusterTemplateList) DeepCopy() *ClusterTemplateList {
+	if in == nil {
+		return nil
+	}
+	out := new(ClusterTemplateList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ClusterTemplateList) 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 *Condition) DeepCopyInto(out *Condition) {
 	*out = *in
@@ -606,6 +665,21 @@ func (in *ParameterDefinition) DeepCopy() *ParameterDefinition {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ParameterValidation) DeepCopyInto(out *ParameterValidation) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterValidation.
+func (in *ParameterValidation) DeepCopy() *ParameterValidation {
+	if in == nil {
+		return nil
+	}
+	out := new(ParameterValidation)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Pipeline) DeepCopyInto(out *Pipeline) {
 	*out = *in
@@ -998,6 +1072,123 @@ func (in SyncWindows) DeepCopy() SyncWindows {
 	return *out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Template) DeepCopyInto(out *Template) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Template.
+func (in *Template) DeepCopy() *Template {
+	if in == nil {
+		return nil
+	}
+	out := new(Template)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *Template) 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 *TemplateList) DeepCopyInto(out *TemplateList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]Template, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateList.
+func (in *TemplateList) DeepCopy() *TemplateList {
+	if in == nil {
+		return nil
+	}
+	out := new(TemplateList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *TemplateList) 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 *TemplateParameter) DeepCopyInto(out *TemplateParameter) {
+	*out = *in
+	in.Default.DeepCopyInto(&out.Default)
+	if in.Validation != nil {
+		in, out := &in.Validation, &out.Validation
+		*out = new(ParameterValidation)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateParameter.
+func (in *TemplateParameter) DeepCopy() *TemplateParameter {
+	if in == nil {
+		return nil
+	}
+	out := new(TemplateParameter)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TemplateSpec) DeepCopyInto(out *TemplateSpec) {
+	*out = *in
+	if in.Parameters != nil {
+		in, out := &in.Parameters, &out.Parameters
+		*out = make([]TemplateParameter, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateSpec.
+func (in *TemplateSpec) DeepCopy() *TemplateSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(TemplateSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TemplateStatus) DeepCopyInto(out *TemplateStatus) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateStatus.
+func (in *TemplateStatus) DeepCopy() *TemplateStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(TemplateStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *TimerTrigger) DeepCopyInto(out *TimerTrigger) {
 	*out = *in
diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go
index af39a70..4ccfb83 100644
--- a/pkg/apiserver/apiserver.go
+++ b/pkg/apiserver/apiserver.go
@@ -21,7 +21,6 @@ import (
 	"context"
 	"fmt"
 	"kubesphere.io/devops/pkg/kapis/common"
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/devops/v1alpha1"
 	"kubesphere.io/devops/pkg/kapis/doc"
 	gitops "kubesphere.io/devops/pkg/kapis/gitops/v1alpha1"
 	"net/http"
@@ -160,9 +159,6 @@ func (s *APIServer) installKubeSphereAPIs() {
 			s.CacheClient,
 			s.Config.AuthenticationOptions),
 	))
-	wss = append(wss, kapisv1alpha1.AddToContainer(s.container, &common.Options{
-		GenericClient: s.Client,
-	})...)
 	wss = append(wss, gitops.AddToContainer(s.container, &common.Options{
 		GenericClient: s.Client,
 	})...)
diff --git a/pkg/kapis/devops/v1alpha1/register.go b/pkg/kapis/devops/v1alpha1/register.go
deleted file mode 100644
index 2ecdf81..0000000
--- a/pkg/kapis/devops/v1alpha1/register.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 v1alpha1
-
-import (
-	"github.com/emicklei/go-restful"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
-	"kubesphere.io/devops/pkg/apiserver/runtime"
-	"kubesphere.io/devops/pkg/kapis/common"
-	"kubesphere.io/devops/pkg/kapis/devops/v1alpha1/template"
-)
-
-// AddToContainer adds web services into web service container.
-func AddToContainer(container *restful.Container, options *common.Options) []*restful.WebService {
-	services := []*restful.WebService{
-		runtime.NewWebService(v1alpha1.GroupVersion),
-		runtime.NewWebServiceWithoutGroup(v1alpha1.GroupVersion),
-	}
-	for _, service := range services {
-		template.RegisterRoutes(service, options)
-		container.Add(service)
-	}
-	return services
-}
diff --git a/pkg/kapis/devops/v1alpha3/common/options.go b/pkg/kapis/devops/v1alpha3/common/options.go
new file mode 100644
index 0000000..126fffa
--- /dev/null
+++ b/pkg/kapis/devops/v1alpha3/common/options.go
@@ -0,0 +1,31 @@
+// 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 common
+
+import (
+	"github.com/emicklei/go-restful"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// Options contain options needed by creating handlers.
+type Options struct {
+	GenericClient client.Client
+}
+
+var (
+	// DevopsPathParameter is a path parameter definition for devops.
+	DevopsPathParameter = restful.PathParameter("devops", "DevOps project name")
+)
diff --git a/pkg/kapis/devops/v1alpha3/register.go b/pkg/kapis/devops/v1alpha3/register.go
index 478b798..fec6877 100644
--- a/pkg/kapis/devops/v1alpha3/register.go
+++ b/pkg/kapis/devops/v1alpha3/register.go
@@ -19,7 +19,9 @@
 package v1alpha3
 
 import (
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/scm"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/template"
 	"net/http"
 
 	restful "github.com/emicklei/go-restful"
@@ -46,20 +48,22 @@ var GroupVersion = schema.GroupVersion{Group: api.GroupName, Version: "v1alpha3"
 // AddToContainer adds web service into container.
 func AddToContainer(container *restful.Container, devopsClient devopsClient.Interface,
 	k8sClient k8s.Client, client client.Client) (wss []*restful.WebService) {
-	ws := runtime.NewWebService(GroupVersion)
-	wss = append(wss, ws)
-	registerRoutes(devopsClient, k8sClient, client, ws)
-	pipelinerun.RegisterRoutes(ws, client)
-	pipeline.RegisterRoutes(ws, client)
-	container.Add(ws)
-
-	ws = runtime.NewWebServiceWithoutGroup(GroupVersion)
-	wss = append(wss, ws)
-	registerRoutes(devopsClient, k8sClient, client, ws)
-	pipelinerun.RegisterRoutes(ws, client)
-	pipeline.RegisterRoutes(ws, client)
-	container.Add(ws)
-	return
+
+	services := []*restful.WebService{
+		runtime.NewWebService(v1alpha3.GroupVersion),
+		runtime.NewWebServiceWithoutGroup(v1alpha3.GroupVersion),
+	}
+
+	for _, service := range services {
+		registerRoutes(devopsClient, k8sClient, client, service)
+		pipelinerun.RegisterRoutes(service, client)
+		pipeline.RegisterRoutes(service, client)
+		template.RegisterRoutes(service, &common.Options{
+			GenericClient: client,
+		})
+		container.Add(service)
+	}
+	return services
 }
 
 func registerRoutes(devopsClient devopsClient.Interface, k8sClient k8s.Client, client client.Client, ws *restful.WebService) {
diff --git a/pkg/kapis/devops/v1alpha1/template/cluster_template_handler.go b/pkg/kapis/devops/v1alpha3/template/cluster_template_handler.go
similarity index 77%
rename from pkg/kapis/devops/v1alpha1/template/cluster_template_handler.go
rename to pkg/kapis/devops/v1alpha3/template/cluster_template_handler.go
index 24d8e72..7cda246 100644
--- a/pkg/kapis/devops/v1alpha1/template/cluster_template_handler.go
+++ b/pkg/kapis/devops/v1alpha3/template/cluster_template_handler.go
@@ -20,10 +20,10 @@ import (
 	"github.com/emicklei/go-restful"
 	"k8s.io/apimachinery/pkg/runtime"
 	"kubesphere.io/devops/pkg/api"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"kubesphere.io/devops/pkg/apiserver/query"
 	"kubesphere.io/devops/pkg/kapis"
-	"kubesphere.io/devops/pkg/models/resources/v1alpha3"
+	resourcev1alpha3 "kubesphere.io/devops/pkg/models/resources/v1alpha3"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
@@ -38,26 +38,26 @@ func (h *handler) handleRenderClusterTemplate(request *restful.Request, response
 }
 
 func (h *handler) queryClusterTemplates(commonQuery *query.Query) (*api.ListResult, error) {
-	templateList := &v1alpha1.ClusterTemplateList{}
-	if err := h.genericClient.List(context.Background(),
+	templateList := &v1alpha3.ClusterTemplateList{}
+	if err := h.List(context.Background(),
 		templateList,
 		client.MatchingLabelsSelector{
 			Selector: commonQuery.Selector(),
 		}); err != nil {
 		return nil, err
 	}
-	return v1alpha3.ToListResult(clusterTemplatesToObjects(templateList.Items), commonQuery, nil), nil
+	return resourcev1alpha3.ToListResult(clusterTemplatesToObjects(templateList.Items), commonQuery, nil), nil
 }
 
-func (h *handler) getClusterTemplate(templateName string) (*v1alpha1.ClusterTemplate, error) {
-	template := &v1alpha1.ClusterTemplate{}
-	if err := h.genericClient.Get(context.Background(), client.ObjectKey{Name: templateName}, template); err != nil {
+func (h *handler) getClusterTemplate(templateName string) (*v1alpha3.ClusterTemplate, error) {
+	template := &v1alpha3.ClusterTemplate{}
+	if err := h.Get(context.Background(), client.ObjectKey{Name: templateName}, template); err != nil {
 		return nil, err
 	}
 	return template, nil
 }
 
-func (h *handler) renderClusterTemplate(templateName string) (v1alpha1.TemplateObject, error) {
+func (h *handler) renderClusterTemplate(templateName string) (v1alpha3.TemplateObject, error) {
 	template, err := h.getClusterTemplate(templateName)
 	if err != nil {
 		return nil, err
@@ -65,7 +65,7 @@ func (h *handler) renderClusterTemplate(templateName string) (v1alpha1.TemplateO
 	return render(template), nil
 }
 
-func clusterTemplatesToObjects(templates []v1alpha1.ClusterTemplate) []runtime.Object {
+func clusterTemplatesToObjects(templates []v1alpha3.ClusterTemplate) []runtime.Object {
 	var objects []runtime.Object
 	for i := range templates {
 		objects = append(objects, &templates[i])
diff --git a/pkg/kapis/devops/v1alpha1/template/handler.go b/pkg/kapis/devops/v1alpha3/template/handler.go
similarity index 79%
rename from pkg/kapis/devops/v1alpha1/template/handler.go
rename to pkg/kapis/devops/v1alpha3/template/handler.go
index 1c161b4..0c03af1 100644
--- a/pkg/kapis/devops/v1alpha1/template/handler.go
+++ b/pkg/kapis/devops/v1alpha3/template/handler.go
@@ -16,16 +16,16 @@
 package template
 
 import (
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/common"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 type handler struct {
-	genericClient client.Client
+	client.Client
 }
 
-func newHandler(options *kapisv1alpha1.Options) *handler {
+func newHandler(options *common.Options) *handler {
 	return &handler{
-		genericClient: options.GenericClient,
+		Client: options.GenericClient,
 	}
 }
diff --git a/pkg/kapis/devops/v1alpha1/template/render.go b/pkg/kapis/devops/v1alpha3/template/render.go
similarity index 89%
rename from pkg/kapis/devops/v1alpha1/template/render.go
rename to pkg/kapis/devops/v1alpha3/template/render.go
index a56d005..50b23ee 100644
--- a/pkg/kapis/devops/v1alpha1/template/render.go
+++ b/pkg/kapis/devops/v1alpha3/template/render.go
@@ -17,11 +17,11 @@ package template
 
 import (
 	"kubesphere.io/devops/pkg/api/devops"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 )
 
-func render(templateObjectCopy v1alpha1.TemplateObject) v1alpha1.TemplateObject {
-	templateObjectCopy = templateObjectCopy.DeepCopyObject().(v1alpha1.TemplateObject)
+func render(templateObjectCopy v1alpha3.TemplateObject) v1alpha3.TemplateObject {
+	templateObjectCopy = templateObjectCopy.DeepCopyObject().(v1alpha3.TemplateObject)
 	// TODO Render template using parameters
 	template := templateObjectCopy.TemplateSpec().Template
 
diff --git a/pkg/kapis/devops/v1alpha1/template/route.go b/pkg/kapis/devops/v1alpha3/template/route.go
similarity index 83%
rename from pkg/kapis/devops/v1alpha1/template/route.go
rename to pkg/kapis/devops/v1alpha3/template/route.go
index 3d5ac72..dc384e7 100644
--- a/pkg/kapis/devops/v1alpha1/template/route.go
+++ b/pkg/kapis/devops/v1alpha3/template/route.go
@@ -21,9 +21,9 @@ import (
 	restfulspec "github.com/emicklei/go-restful-openapi"
 	"kubesphere.io/devops/pkg/api"
 	"kubesphere.io/devops/pkg/api/devops"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"kubesphere.io/devops/pkg/constants"
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/common"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"net/http"
 )
 
@@ -36,35 +36,35 @@ var (
 
 // PageResult is the model of Template page result.
 type PageResult struct {
-	Items []v1alpha1.Template `json:"items"`
+	Items []v1alpha3.Template `json:"items"`
 	Total int                 `json:"total"`
 }
 
 // RegisterRoutes is for registering template routes into WebService.
-func RegisterRoutes(service *restful.WebService, options *kapisv1alpha1.Options) {
+func RegisterRoutes(service *restful.WebService, options *common.Options) {
 	handler := newHandler(options)
 	// Template
 	service.Route(service.GET("/devops/{devops}/templates").
 		To(handler.handleQuery).
-		Param(kapisv1alpha1.DevopsPathParameter).
+		Param(common.DevopsPathParameter).
 		Doc("Query templates for a DevOps Project.").
 		Returns(http.StatusOK, api.StatusOK, PageResult{}).
 		Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsTemplateTag}))
 
 	service.Route(service.GET("/devops/{devops}/templates/{template}").
 		To(handler.handleGetTemplate).
-		Param(kapisv1alpha1.DevopsPathParameter).
+		Param(common.DevopsPathParameter).
 		Param(TemplatePathParameter).
 		Doc("Get template").
-		Returns(http.StatusOK, api.StatusOK, v1alpha1.Template{}).
+		Returns(http.StatusOK, api.StatusOK, v1alpha3.Template{}).
 		Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsTemplateTag}))
 
 	service.Route(service.POST("/devops/{devops}/templates/{template}/render").
 		To(handler.handleRenderTemplate).
-		Param(kapisv1alpha1.DevopsPathParameter).
+		Param(common.DevopsPathParameter).
 		Param(TemplatePathParameter).
 		Doc(fmt.Sprintf("Render template and return render result into annotations (%s/%s) inside template", devops.GroupName, devops.RenderResultAnnoKey)).
-		Returns(http.StatusOK, api.StatusOK, v1alpha1.Template{}).
+		Returns(http.StatusOK, api.StatusOK, v1alpha3.Template{}).
 		Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsTemplateTag}))
 
 	// ClusterTemplate
@@ -78,6 +78,6 @@ func RegisterRoutes(service *restful.WebService, options *kapisv1alpha1.Options)
 		To(handler.handleRenderClusterTemplate).
 		Param(ClusterTemplatePathParameter).
 		Doc("Render cluster template.").
-		Returns(http.StatusOK, api.StatusOK, v1alpha1.ClusterTemplate{}).
+		Returns(http.StatusOK, api.StatusOK, v1alpha3.ClusterTemplate{}).
 		Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsClusterTemplateTag}))
 }
diff --git a/pkg/kapis/devops/v1alpha1/template/template_handler.go b/pkg/kapis/devops/v1alpha3/template/template_handler.go
similarity index 72%
rename from pkg/kapis/devops/v1alpha1/template/template_handler.go
rename to pkg/kapis/devops/v1alpha3/template/template_handler.go
index f156c53..d32bf14 100644
--- a/pkg/kapis/devops/v1alpha1/template/template_handler.go
+++ b/pkg/kapis/devops/v1alpha3/template/template_handler.go
@@ -20,24 +20,24 @@ import (
 	"github.com/emicklei/go-restful"
 	"k8s.io/apimachinery/pkg/runtime"
 	"kubesphere.io/devops/pkg/api"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"kubesphere.io/devops/pkg/apiserver/query"
 	"kubesphere.io/devops/pkg/kapis"
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/common"
-	"kubesphere.io/devops/pkg/models/resources/v1alpha3"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
+	resourcev1alpha3 "kubesphere.io/devops/pkg/models/resources/v1alpha3"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 func (h *handler) handleQuery(request *restful.Request, response *restful.Response) {
-	devopsName := request.PathParameter(kapisv1alpha1.DevopsPathParameter.Data().Name)
+	devopsName := request.PathParameter(common.DevopsPathParameter.Data().Name)
 	commonQuery := query.ParseQueryParameter(request)
 
 	kapis.ResponseWriter{Response: response}.WriteEntityOrError(h.queryTemplate(devopsName, commonQuery))
 }
 
 func (h *handler) queryTemplate(devopsName string, commonQuery *query.Query) (*api.ListResult, error) {
-	templateList := &v1alpha1.TemplateList{}
-	if err := h.genericClient.List(context.Background(),
+	templateList := &v1alpha3.TemplateList{}
+	if err := h.List(context.Background(),
 		templateList,
 		client.InNamespace(devopsName),
 		client.MatchingLabelsSelector{
@@ -45,32 +45,32 @@ func (h *handler) queryTemplate(devopsName string, commonQuery *query.Query) (*a
 		}); err != nil {
 		return nil, err
 	}
-	return v1alpha3.ToListResult(templatesToObjects(templateList.Items), commonQuery, nil), nil
+	return resourcev1alpha3.ToListResult(templatesToObjects(templateList.Items), commonQuery, nil), nil
 }
 
 func (h *handler) handleGetTemplate(request *restful.Request, response *restful.Response) {
-	devopsName := request.PathParameter(kapisv1alpha1.DevopsPathParameter.Data().Name)
+	devopsName := request.PathParameter(common.DevopsPathParameter.Data().Name)
 	templateName := request.PathParameter(TemplatePathParameter.Data().Name)
 
 	kapis.ResponseWriter{Response: response}.WriteEntityOrError(h.getTemplate(devopsName, templateName))
 }
 
-func (h *handler) getTemplate(devopsName, templateName string) (*v1alpha1.Template, error) {
-	template := &v1alpha1.Template{}
-	if err := h.genericClient.Get(context.Background(), client.ObjectKey{Namespace: devopsName, Name: templateName}, template); err != nil {
+func (h *handler) getTemplate(devopsName, templateName string) (*v1alpha3.Template, error) {
+	template := &v1alpha3.Template{}
+	if err := h.Get(context.Background(), client.ObjectKey{Namespace: devopsName, Name: templateName}, template); err != nil {
 		return nil, err
 	}
 	return template, nil
 }
 
 func (h *handler) handleRenderTemplate(request *restful.Request, response *restful.Response) {
-	devopsName := request.PathParameter(kapisv1alpha1.DevopsPathParameter.Data().Name)
+	devopsName := request.PathParameter(common.DevopsPathParameter.Data().Name)
 	templateName := request.PathParameter(TemplatePathParameter.Data().Name)
 
 	kapis.ResponseWriter{Response: response}.WriteEntityOrError(h.renderTemplate(devopsName, templateName))
 }
 
-func (h *handler) renderTemplate(devopsName, templateName string) (v1alpha1.TemplateObject, error) {
+func (h *handler) renderTemplate(devopsName, templateName string) (v1alpha3.TemplateObject, error) {
 	tmpl, err := h.getTemplate(devopsName, templateName)
 	if err != nil {
 		return nil, err
@@ -78,7 +78,7 @@ func (h *handler) renderTemplate(devopsName, templateName string) (v1alpha1.Temp
 	return render(tmpl), nil
 }
 
-func templatesToObjects(templates []v1alpha1.Template) []runtime.Object {
+func templatesToObjects(templates []v1alpha3.Template) []runtime.Object {
 	var objects []runtime.Object
 	for i := range templates {
 		objects = append(objects, &templates[i])


Test patch:
diff --git a/pkg/kapis/devops/v1alpha1/template/cluster_template_handler_test.go b/pkg/kapis/devops/v1alpha3/template/cluster_template_handler_test.go
similarity index 90%
rename from pkg/kapis/devops/v1alpha1/template/cluster_template_handler_test.go
rename to pkg/kapis/devops/v1alpha3/template/cluster_template_handler_test.go
index e10ee23..80049c6 100644
--- a/pkg/kapis/devops/v1alpha1/template/cluster_template_handler_test.go
+++ b/pkg/kapis/devops/v1alpha3/template/cluster_template_handler_test.go
@@ -25,7 +25,6 @@ import (
 	"k8s.io/client-go/kubernetes/scheme"
 	"kubesphere.io/devops/pkg/api"
 	"kubesphere.io/devops/pkg/api/devops"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
 	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"net/http"
 	"net/http/httptest"
@@ -35,15 +34,15 @@ import (
 )
 
 func Test_clusterTemplatesToObjects(t *testing.T) {
-	createTemplate := func(name string) *v1alpha1.ClusterTemplate {
-		return &v1alpha1.ClusterTemplate{
+	createTemplate := func(name string) *v1alpha3.ClusterTemplate {
+		return &v1alpha3.ClusterTemplate{
 			ObjectMeta: metav1.ObjectMeta{
 				Name: name,
 			},
 		}
 	}
 	type args struct {
-		templates []v1alpha1.ClusterTemplate
+		templates []v1alpha3.ClusterTemplate
 	}
 	tests := []struct {
 		name string
@@ -52,7 +51,7 @@ func Test_clusterTemplatesToObjects(t *testing.T) {
 	}{{
 		name: "Should convert correctly",
 		args: args{
-			templates: []v1alpha1.ClusterTemplate{
+			templates: []v1alpha3.ClusterTemplate{
 				*createTemplate("template1"),
 				*createTemplate("template2"),
 			},
@@ -70,7 +69,7 @@ func Test_clusterTemplatesToObjects(t *testing.T) {
 	}, {
 		name: "Should return nil if templates argument is an empty slice",
 		args: args{
-			templates: []v1alpha1.ClusterTemplate{},
+			templates: []v1alpha3.ClusterTemplate{},
 		},
 		want: nil,
 	},
@@ -85,8 +84,8 @@ func Test_clusterTemplatesToObjects(t *testing.T) {
 }
 
 func Test_handler_handleQueryClusterTemplates(t *testing.T) {
-	createTemplate := func(name string) *v1alpha1.ClusterTemplate {
-		return &v1alpha1.ClusterTemplate{
+	createTemplate := func(name string) *v1alpha3.ClusterTemplate {
+		return &v1alpha3.ClusterTemplate{
 			ObjectMeta: metav1.ObjectMeta{
 				Name: name,
 			},
@@ -148,13 +147,12 @@ func Test_handler_handleQueryClusterTemplates(t *testing.T) {
 	},
 	}
 	for _, tt := range tests {
-		utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
 		utilruntime.Must(v1alpha3.AddToScheme(scheme.Scheme))
 		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tt.args.initObjects...)
 
 		t.Run(tt.name, func(t *testing.T) {
 			h := &handler{
-				genericClient: fakeClient,
+				Client: fakeClient,
 			}
 			request := tt.args.request
 			recorder := httptest.NewRecorder()
@@ -171,11 +169,11 @@ func Test_handler_handleQueryClusterTemplates(t *testing.T) {
 }
 
 func Test_handler_handleRenderClusterTemplate(t *testing.T) {
-	fakeTemplate := &v1alpha1.ClusterTemplate{
+	fakeTemplate := &v1alpha3.ClusterTemplate{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "fake-template",
 		},
-		Spec: v1alpha1.TemplateSpec{
+		Spec: v1alpha3.TemplateSpec{
 			Template: "fake template content",
 		},
 	}
@@ -213,19 +211,18 @@ func Test_handler_handleRenderClusterTemplate(t *testing.T) {
 		},
 		wantCode: 200,
 		assertion: func(t *testing.T, recorder *httptest.ResponseRecorder) {
-			gotTemplate := &v1alpha1.Template{}
+			gotTemplate := &v1alpha3.Template{}
 			_ = json.Unmarshal(recorder.Body.Bytes(), gotTemplate)
 			renderResult := gotTemplate.GetAnnotations()[devops.GroupName+devops.RenderResultAnnoKey]
 			assert.Equal(t, fakeTemplate.Spec.Template, renderResult)
 		},
 	}}
 	for _, tt := range tests {
-		utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
 		utilruntime.Must(v1alpha3.AddToScheme(scheme.Scheme))
 		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tt.args.initObjects...)
 		t.Run(tt.name, func(t *testing.T) {
 			h := &handler{
-				genericClient: fakeClient,
+				Client: fakeClient,
 			}
 
 			recorder := httptest.NewRecorder()
diff --git a/pkg/kapis/devops/v1alpha1/template/handler_test.go b/pkg/kapis/devops/v1alpha3/template/handler_test.go
similarity index 89%
rename from pkg/kapis/devops/v1alpha1/template/handler_test.go
rename to pkg/kapis/devops/v1alpha3/template/handler_test.go
index 7af182d..4f1e05c 100644
--- a/pkg/kapis/devops/v1alpha1/template/handler_test.go
+++ b/pkg/kapis/devops/v1alpha3/template/handler_test.go
@@ -16,7 +16,7 @@ package template
 
 import (
 	"k8s.io/client-go/kubernetes/scheme"
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/common"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"reflect"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 	"testing"
@@ -25,7 +25,7 @@ import (
 func Test_newHandler(t *testing.T) {
 	fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme)
 	type args struct {
-		options *kapisv1alpha1.Options
+		options *common.Options
 	}
 	tests := []struct {
 		name string
@@ -34,12 +34,12 @@ func Test_newHandler(t *testing.T) {
 	}{{
 		name: "Should set handler correctly",
 		args: args{
-			options: &kapisv1alpha1.Options{
+			options: &common.Options{
 				GenericClient: fakeClient,
 			},
 		},
 		want: &handler{
-			genericClient: fakeClient,
+			Client: fakeClient,
 		},
 	},
 	}
diff --git a/pkg/kapis/devops/v1alpha1/template/render_test.go b/pkg/kapis/devops/v1alpha3/template/render_test.go
similarity index 83%
rename from pkg/kapis/devops/v1alpha1/template/render_test.go
rename to pkg/kapis/devops/v1alpha3/template/render_test.go
index 98c7fc5..cb68b8c 100644
--- a/pkg/kapis/devops/v1alpha1/template/render_test.go
+++ b/pkg/kapis/devops/v1alpha3/template/render_test.go
@@ -19,31 +19,31 @@ import (
 	"github.com/stretchr/testify/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"kubesphere.io/devops/pkg/api/devops"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
 	"testing"
 )
 
 func Test_render(t *testing.T) {
 	type args struct {
-		templateObject v1alpha1.TemplateObject
+		templateObject v1alpha3.TemplateObject
 	}
 	tests := []struct {
 		name   string
 		args   args
-		verify func(t *testing.T, object v1alpha1.TemplateObject)
+		verify func(t *testing.T, object v1alpha3.TemplateObject)
 	}{{
 		name: "Should render template into annotations",
 		args: args{
-			templateObject: &v1alpha1.Template{
+			templateObject: &v1alpha3.Template{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "fake-template",
 				},
-				Spec: v1alpha1.TemplateSpec{
+				Spec: v1alpha3.TemplateSpec{
 					Template: "fake-template-content",
 				},
 			},
 		},
-		verify: func(t *testing.T, object v1alpha1.TemplateObject) {
+		verify: func(t *testing.T, object v1alpha3.TemplateObject) {
 			gotRenderResult := object.GetAnnotations()[devops.GroupName+devops.RenderResultAnnoKey]
 			wantRenderResult := object.TemplateSpec().Template
 			assert.Equal(t, wantRenderResult, gotRenderResult)
diff --git a/pkg/kapis/devops/v1alpha1/register_test.go b/pkg/kapis/devops/v1alpha3/template/route_test.go
similarity index 64%
rename from pkg/kapis/devops/v1alpha1/register_test.go
rename to pkg/kapis/devops/v1alpha3/template/route_test.go
index d72842a..bc25990 100644
--- a/pkg/kapis/devops/v1alpha1/register_test.go
+++ b/pkg/kapis/devops/v1alpha3/template/route_test.go
@@ -12,7 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 //
-package v1alpha1
+
+package template
 
 import (
 	"fmt"
@@ -20,15 +21,16 @@ import (
 	"github.com/stretchr/testify/assert"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
-	"kubesphere.io/devops/pkg/kapis/common"
+	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
+	"kubesphere.io/devops/pkg/apiserver/runtime"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"net/http"
 	"net/http/httptest"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 	"testing"
 )
 
-func TestAPIsExist(t *testing.T) {
+func TestRegisterRoutes(t *testing.T) {
 	type args struct {
 		method string
 		uri    string
@@ -68,24 +70,25 @@ func TestAPIsExist(t *testing.T) {
 		},
 	}}
 	for _, tt := range tests {
-		container := restful.NewContainer()
-		utilruntime.Must(v1alpha1.SchemeBuilder.AddToScheme(scheme.Scheme))
-		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme)
-		AddToContainer(container, &common.Options{
-			GenericClient: fakeClient,
-		})
 		t.Run(tt.name, func(t *testing.T) {
-			uriWithGroupVersion := fmt.Sprintf("/kapis/%s/%s%s",
-				v1alpha1.GroupVersion.Group, v1alpha1.GroupVersion.Version, tt.args.uri)
-			uriWithVersion := fmt.Sprintf("/%s%s",
-				v1alpha1.GroupVersion.Version, tt.args.uri)
-			for _, uri := range []string{uriWithVersion, uriWithGroupVersion} {
-				recorder := httptest.NewRecorder()
-				request, _ := http.NewRequest(tt.args.method, uri, nil)
-				container.ServeHTTP(recorder, request)
-				if recorder.Code == 404 {
-					assert.NotEqual(t, "404 page not found\n", recorder.Body.String())
-				}
+			container := restful.NewContainer()
+			utilruntime.Must(v1alpha3.SchemeBuilder.AddToScheme(scheme.Scheme))
+			fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme)
+			service := runtime.NewWebService(v1alpha3.GroupVersion)
+			RegisterRoutes(service, &common.Options{
+				GenericClient: fakeClient,
+			})
+			container.Add(service)
+
+			uri := fmt.Sprintf("/kapis/%s/%s%s",
+				v1alpha3.GroupVersion.Group, v1alpha3.GroupVersion.Version, tt.args.uri)
+			recorder := httptest.NewRecorder()
+			request, _ := http.NewRequest(tt.args.method, uri, nil)
+			container.ServeHTTP(recorder, request)
+			if recorder.Code == 404 {
+				assert.NotContains(t, recorder.Body.String(), "Page Not Found")
+			} else {
+				assert.Equal(t, 200, recorder.Code)
 			}
 		})
 	}
diff --git a/pkg/kapis/devops/v1alpha1/template/template_handler_test.go b/pkg/kapis/devops/v1alpha3/template/template_handler_test.go
similarity index 88%
rename from pkg/kapis/devops/v1alpha1/template/template_handler_test.go
rename to pkg/kapis/devops/v1alpha3/template/template_handler_test.go
index d1a130d..01c6c30 100644
--- a/pkg/kapis/devops/v1alpha1/template/template_handler_test.go
+++ b/pkg/kapis/devops/v1alpha3/template/template_handler_test.go
@@ -25,9 +25,8 @@ import (
 	"k8s.io/client-go/kubernetes/scheme"
 	"kubesphere.io/devops/pkg/api"
 	"kubesphere.io/devops/pkg/api/devops"
-	"kubesphere.io/devops/pkg/api/devops/v1alpha1"
 	"kubesphere.io/devops/pkg/api/devops/v1alpha3"
-	kapisv1alpha1 "kubesphere.io/devops/pkg/kapis/common"
+	"kubesphere.io/devops/pkg/kapis/devops/v1alpha3/common"
 	"net/http"
 	"net/http/httptest"
 	"reflect"
@@ -36,8 +35,8 @@ import (
 )
 
 func Test_templatesToObjects(t *testing.T) {
-	createTemplate := func(name string) *v1alpha1.Template {
-		return &v1alpha1.Template{
+	createTemplate := func(name string) *v1alpha3.Template {
+		return &v1alpha3.Template{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      name,
 				Namespace: "fake-namespace",
@@ -45,7 +44,7 @@ func Test_templatesToObjects(t *testing.T) {
 		}
 	}
 	type args struct {
-		templates []v1alpha1.Template
+		templates []v1alpha3.Template
 	}
 	tests := []struct {
 		name string
@@ -54,7 +53,7 @@ func Test_templatesToObjects(t *testing.T) {
 	}{{
 		name: "Should convert correctly",
 		args: args{
-			templates: []v1alpha1.Template{
+			templates: []v1alpha3.Template{
 				*createTemplate("template1"),
 				*createTemplate("template2"),
 			},
@@ -72,7 +71,7 @@ func Test_templatesToObjects(t *testing.T) {
 	}, {
 		name: "Should return nil if templates argument is an empty slice",
 		args: args{
-			templates: []v1alpha1.Template{},
+			templates: []v1alpha3.Template{},
 		},
 		want: nil,
 	},
@@ -86,8 +85,8 @@ func Test_templatesToObjects(t *testing.T) {
 	}
 }
 func Test_handler_handleQueryTemplates(t *testing.T) {
-	createTemplate := func(name string) *v1alpha1.Template {
-		return &v1alpha1.Template{
+	createTemplate := func(name string) *v1alpha3.Template {
+		return &v1alpha3.Template{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      name,
 				Namespace: "fake-devops",
@@ -97,7 +96,7 @@ func Test_handler_handleQueryTemplates(t *testing.T) {
 	createRequest := func(uri, devopsName string) *restful.Request {
 		fakeRequest := httptest.NewRequest(http.MethodGet, uri, nil)
 		request := restful.NewRequest(fakeRequest)
-		request.PathParameters()[kapisv1alpha1.DevopsPathParameter.Data().Name] = devopsName
+		request.PathParameters()[common.DevopsPathParameter.Data().Name] = devopsName
 		return request
 	}
 	type args struct {
@@ -151,13 +150,12 @@ func Test_handler_handleQueryTemplates(t *testing.T) {
 	},
 	}
 	for _, tt := range tests {
-		utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
 		utilruntime.Must(v1alpha3.AddToScheme(scheme.Scheme))
 		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tt.args.initObjects...)
 
 		t.Run(tt.name, func(t *testing.T) {
 			h := &handler{
-				genericClient: fakeClient,
+				Client: fakeClient,
 			}
 			request := tt.args.request
 			recorder := httptest.NewRecorder()
@@ -174,7 +172,7 @@ func Test_handler_handleQueryTemplates(t *testing.T) {
 }
 
 func Test_handler_handleGetTemplate(t *testing.T) {
-	fakeTemplate := &v1alpha1.Template{
+	fakeTemplate := &v1alpha3.Template{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "fake-template",
 			Namespace: "fake-devops",
@@ -183,7 +181,7 @@ func Test_handler_handleGetTemplate(t *testing.T) {
 	createRequest := func(uri, devopsName, templateName string) *restful.Request {
 		fakeRequest := httptest.NewRequest(http.MethodGet, uri, nil)
 		request := restful.NewRequest(fakeRequest)
-		request.PathParameters()[kapisv1alpha1.DevopsPathParameter.Data().Name] = devopsName
+		request.PathParameters()[common.DevopsPathParameter.Data().Name] = devopsName
 		request.PathParameters()[TemplatePathParameter.Data().Name] = templateName
 		return request
 	}
@@ -213,7 +211,7 @@ func Test_handler_handleGetTemplate(t *testing.T) {
 		},
 		wantCode: 200,
 		assertion: func(t *testing.T, recorder *httptest.ResponseRecorder) {
-			gotTemplate := &v1alpha1.Template{}
+			gotTemplate := &v1alpha3.Template{}
 			_ = json.Unmarshal(recorder.Body.Bytes(), gotTemplate)
 			assert.Equal(t, fakeTemplate.ObjectMeta, gotTemplate.ObjectMeta)
 			assert.Equal(t, fakeTemplate.Spec, gotTemplate.Spec)
@@ -221,13 +219,12 @@ func Test_handler_handleGetTemplate(t *testing.T) {
 		},
 	}}
 	for _, tt := range tests {
-		utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
 		utilruntime.Must(v1alpha3.AddToScheme(scheme.Scheme))
 		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tt.args.initObjects...)
 
 		t.Run(tt.name, func(t *testing.T) {
 			h := &handler{
-				genericClient: fakeClient,
+				Client: fakeClient,
 			}
 			recorder := httptest.NewRecorder()
 			response := restful.NewResponse(recorder)
@@ -243,19 +240,19 @@ func Test_handler_handleGetTemplate(t *testing.T) {
 }
 
 func Test_handler_handleRenderTemplate(t *testing.T) {
-	fakeTemplate := &v1alpha1.Template{
+	fakeTemplate := &v1alpha3.Template{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "fake-template",
 			Namespace: "fake-devops",
 		},
-		Spec: v1alpha1.TemplateSpec{
+		Spec: v1alpha3.TemplateSpec{
 			Template: "fake template content",
 		},
 	}
 	createRequest := func(uri, devopsName, templateName string) *restful.Request {
 		fakeRequest := httptest.NewRequest(http.MethodGet, uri, nil)
 		request := restful.NewRequest(fakeRequest)
-		request.PathParameters()[kapisv1alpha1.DevopsPathParameter.Data().Name] = devopsName
+		request.PathParameters()[common.DevopsPathParameter.Data().Name] = devopsName
 		request.PathParameters()[TemplatePathParameter.Data().Name] = templateName
 		return request
 	}
@@ -287,19 +284,18 @@ func Test_handler_handleRenderTemplate(t *testing.T) {
 		},
 		wantCode: 200,
 		assertion: func(t *testing.T, recorder *httptest.ResponseRecorder) {
-			gotTemplate := &v1alpha1.Template{}
+			gotTemplate := &v1alpha3.Template{}
 			_ = json.Unmarshal(recorder.Body.Bytes(), gotTemplate)
 			renderResult := gotTemplate.GetAnnotations()[devops.GroupName+devops.RenderResultAnnoKey]
 			assert.Equal(t, fakeTemplate.Spec.Template, renderResult)
 		},
 	}}
 	for _, tt := range tests {
-		utilruntime.Must(v1alpha1.AddToScheme(scheme.Scheme))
 		utilruntime.Must(v1alpha3.AddToScheme(scheme.Scheme))
 		fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tt.args.initObjects...)
 		t.Run(tt.name, func(t *testing.T) {
 			h := &handler{
-				genericClient: fakeClient,
+				Client: fakeClient,
 			}
 
 			recorder := httptest.NewRecorder()