Skip to content

Commit ac1000a

Browse files
SergKMykolaMarusenko
authored andcommitted
feat: add tektonDisabled field and ciTool enum validation for multi-CI support
- Add TektonDisabled boolean to GitServerSpec to gate EventListener/Ingress/Route creation. Allows GitServers to opt-out of Tekton infrastructure when using native CI systems (GitLab CI, GitHub Actions) or externally-managed webhooks. - Add enum validation (tekton|gitlab) to Codebase.Spec.CiTool. Prevents silent misconfiguration where invalid CI tool values would pass validation but provide no CI execution. Backward compatible: enum only validates on create/update, existing CRs remain valid until modified. - Skip Tekton pipeline name generation in CodebaseBranch.setDefaultValues when ciTool=gitlab, since GitLab CI uses .gitlab-ci.yml instead of Tekton pipelines. Avoids unnecessary API calls and generated pipeline names that would be unused. - Bump Tekton Triggers API version from v1alpha1 to v1beta1, aligning with operator's v0.34.0 dependency. v1alpha1 was removed in v0.28.0; v1beta1 is the stable API. No EventListener spec changes needed. Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
1 parent 7e607c7 commit ac1000a

12 files changed

Lines changed: 219 additions & 3 deletions

api/v1/codebase_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ type CodebaseSpec struct {
105105

106106
// A name of tool which should be used as CI.
107107
// +optional
108+
// +kubebuilder:validation:Enum=tekton;gitlab
108109
// +kubebuilder:default:=tekton
109110
CiTool string `json:"ciTool"`
110111

api/v1/git_server_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ type GitServerSpec struct {
5151
// +optional
5252
// +kubebuilder:example:=`https://webhook-url.com`
5353
WebhookUrl string `json:"webhookUrl,omitempty"`
54+
55+
// TektonDisabled disables creation of Tekton EventListener and associated
56+
// Ingress/Route resources for this GitServer.
57+
// Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions)
58+
// is used instead of Tekton, or when webhook endpoints are managed externally.
59+
// +optional
60+
TektonDisabled bool `json:"tektonDisabled,omitempty"`
5461
}
5562

5663
// GitServerStatus defines the observed state of GitServer.

config/crd/bases/v2.edp.epam.com_codebases.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ spec:
7373
ciTool:
7474
default: tekton
7575
description: A name of tool which should be used as CI.
76+
enum:
77+
- tekton
78+
- gitlab
7679
type: string
7780
cloneRepositoryCredentials:
7881
description: CloneRepositoryCredentials contains reference to secret

config/crd/bases/v2.edp.epam.com_gitservers.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ spec:
9292
sshPort:
9393
format: int32
9494
type: integer
95+
tektonDisabled:
96+
description: |-
97+
TektonDisabled disables creation of Tekton EventListener and associated
98+
Ingress/Route resources for this GitServer.
99+
Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions)
100+
is used instead of Tekton, or when webhook endpoints are managed externally.
101+
type: boolean
95102
webhookUrl:
96103
description: |-
97104
WebhookUrl is a URL for webhook that will be created in the git provider.

controllers/codebasebranch/codebasebranch_controller.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@ func (r *ReconcileCodebaseBranch) setDefaultValues(
331331
return false, nil
332332
}
333333

334+
// GitLab CI codebases use .gitlab-ci.yml for pipeline configuration,
335+
// so there is no need to generate Tekton pipeline names.
336+
if codebase.Spec.CiTool == util.CIGitLab {
337+
return false, nil
338+
}
339+
334340
gitServer := &codebaseApi.GitServer{}
335341
if err := r.client.Get(ctx, types.NamespacedName{
336342
Name: codebase.Spec.GitServer,

controllers/codebasebranch/codebasebranch_controller_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldSetPipelines(t *testing.T) {
534534
BuildTool: "go",
535535
Type: "application",
536536
GitServer: "test-gs",
537+
CiTool: util.CITekton,
537538
Versioning: codebaseApi.Versioning{
538539
Type: codebaseApi.VersioningTypDefault,
539540
},
@@ -609,6 +610,7 @@ func TestReconcileCodebaseBranch_Reconcile_FailedToSetPipelines_GitServerNotFoun
609610
BuildTool: "go",
610611
Type: "application",
611612
GitServer: "test-gs",
613+
CiTool: util.CITekton,
612614
Versioning: codebaseApi.Versioning{
613615
Type: codebaseApi.VersioningTypDefault,
614616
},
@@ -634,3 +636,108 @@ func TestReconcileCodebaseBranch_Reconcile_FailedToSetPipelines_GitServerNotFoun
634636
require.Error(t, err)
635637
require.Contains(t, err.Error(), "failed to get GitServer")
636638
}
639+
640+
func TestReconcileCodebaseBranch_Reconcile_ShouldSkipPipelinesForGitLab(t *testing.T) {
641+
cb := &codebaseApi.CodebaseBranch{
642+
ObjectMeta: metaV1.ObjectMeta{
643+
Name: "test-branch",
644+
Namespace: "default",
645+
},
646+
Spec: codebaseApi.CodebaseBranchSpec{
647+
CodebaseName: "test-codebase",
648+
BranchName: "test-branch",
649+
},
650+
}
651+
c := &codebaseApi.Codebase{
652+
ObjectMeta: metaV1.ObjectMeta{
653+
Name: "test-codebase",
654+
Namespace: "default",
655+
},
656+
Spec: codebaseApi.CodebaseSpec{
657+
Lang: "go",
658+
Framework: "gin",
659+
BuildTool: "go",
660+
Type: "application",
661+
GitServer: "test-gs",
662+
CiTool: util.CIGitLab,
663+
Versioning: codebaseApi.Versioning{
664+
Type: codebaseApi.VersioningTypDefault,
665+
},
666+
},
667+
}
668+
gs := &codebaseApi.GitServer{
669+
ObjectMeta: metaV1.ObjectMeta{
670+
Name: "test-gs",
671+
Namespace: "default",
672+
},
673+
Spec: codebaseApi.GitServerSpec{
674+
GitProvider: codebaseApi.GitProviderGithub,
675+
},
676+
}
677+
678+
scheme := runtime.NewScheme()
679+
require.NoError(t, codebaseApi.AddToScheme(scheme))
680+
681+
fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb, gs).WithStatusSubresource(cb).Build()
682+
683+
req := reconcile.Request{
684+
NamespacedName: types.NamespacedName{
685+
Name: "test-branch",
686+
Namespace: "default",
687+
},
688+
}
689+
690+
controller := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard())
691+
692+
_, err := controller.Reconcile(context.Background(), req)
693+
694+
require.NoError(t, err)
695+
696+
updatedCb := &codebaseApi.CodebaseBranch{}
697+
err = fakeCl.Get(
698+
context.Background(),
699+
types.NamespacedName{
700+
Name: "test-branch",
701+
Namespace: "default",
702+
},
703+
updatedCb,
704+
)
705+
706+
require.NoError(t, err)
707+
assert.Nil(t, updatedCb.Spec.Pipelines)
708+
}
709+
710+
func TestSetDefaultValues_ShouldSkipForGitLab(t *testing.T) {
711+
cb := &codebaseApi.CodebaseBranch{
712+
ObjectMeta: metaV1.ObjectMeta{
713+
Name: "test-branch",
714+
Namespace: "default",
715+
},
716+
Spec: codebaseApi.CodebaseBranchSpec{
717+
CodebaseName: "test-codebase",
718+
BranchName: "test-branch",
719+
},
720+
}
721+
c := &codebaseApi.Codebase{
722+
ObjectMeta: metaV1.ObjectMeta{
723+
Name: "test-codebase",
724+
Namespace: "default",
725+
},
726+
Spec: codebaseApi.CodebaseSpec{
727+
CiTool: util.CIGitLab,
728+
},
729+
}
730+
731+
scheme := runtime.NewScheme()
732+
require.NoError(t, codebaseApi.AddToScheme(scheme))
733+
734+
fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb).Build()
735+
736+
r := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard())
737+
738+
changed, err := r.setDefaultValues(context.Background(), cb, c)
739+
740+
require.NoError(t, err)
741+
assert.False(t, changed)
742+
assert.Nil(t, cb.Spec.Pipelines)
743+
}

controllers/gitserver/create_event_listener.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ func NewCreateEventListener(k8sClient client.Client) *CreateEventListener {
3030
func (h *CreateEventListener) ServeRequest(ctx context.Context, gitServer *codebaseApi.GitServer) error {
3131
log := ctrl.LoggerFrom(ctx)
3232

33+
if gitServer.Spec.TektonDisabled {
34+
log.Info("Skip creating EventListener because Tekton is disabled")
35+
return nil
36+
}
37+
3338
if gitServer.Spec.WebhookUrl != "" {
3439
log.Info("Skip creating EventListener because webhook URL is set")
3540
return nil
@@ -53,7 +58,7 @@ func (h *CreateEventListener) createEventListener(ctx context.Context, gitServer
5358

5459
// Use Unstructured to avoid direct dependency on "knative.dev/pkg/apis/duck/v1" because EventListener relies on it.
5560
// This dependency can conflict with the operator's dependencies.
56-
// https://github.com/tektoncd/triggers/blob/v0.27.0/pkg/apis/triggers/v1beta1/event_listener_types.go#L86
61+
// https://github.com/tektoncd/triggers/blob/v0.34.0/pkg/apis/triggers/v1beta1/event_listener_types.go#L86
5762
el := tektoncd.NewEventListenerUnstructured()
5863
elName := generateEventListenerName(gitServer.Name)
5964

controllers/gitserver/create_event_listener_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,65 @@ func TestCreateEventListener_ServeRequest(t *testing.T) {
3737
wantErr require.ErrorAssertionFunc
3838
want func(t *testing.T, k8sClient client.Client)
3939
}{
40+
{
41+
name: "skip creating event listener because tekton is disabled",
42+
gitServer: &codebaseApi.GitServer{
43+
ObjectMeta: controllerruntime.ObjectMeta{
44+
Name: "test-git-server",
45+
Namespace: "default",
46+
},
47+
Spec: codebaseApi.GitServerSpec{
48+
TektonDisabled: true,
49+
},
50+
},
51+
k8sClient: func(t *testing.T) client.Client {
52+
return fake.NewClientBuilder().WithScheme(scheme).Build()
53+
},
54+
wantErr: require.NoError,
55+
want: func(t *testing.T, k8sClient client.Client) {
56+
el := tektoncd.NewEventListenerUnstructured()
57+
err := k8sClient.Get(context.Background(), client.ObjectKey{
58+
Namespace: "default",
59+
Name: generateEventListenerName("test-git-server"),
60+
}, el)
61+
require.Error(t, err)
62+
require.True(t, k8sErrors.IsNotFound(err))
63+
64+
i := &networkingv1.Ingress{}
65+
err = k8sClient.Get(context.Background(), client.ObjectKey{
66+
Namespace: "default",
67+
Name: GenerateIngressName("test-git-server"),
68+
}, i)
69+
require.Error(t, err)
70+
require.True(t, k8sErrors.IsNotFound(err))
71+
},
72+
},
73+
{
74+
name: "skip creating event listener because tekton is disabled even with webhook URL set",
75+
gitServer: &codebaseApi.GitServer{
76+
ObjectMeta: controllerruntime.ObjectMeta{
77+
Name: "test-git-server",
78+
Namespace: "default",
79+
},
80+
Spec: codebaseApi.GitServerSpec{
81+
TektonDisabled: true,
82+
WebhookUrl: "https://external-webhook",
83+
},
84+
},
85+
k8sClient: func(t *testing.T) client.Client {
86+
return fake.NewClientBuilder().WithScheme(scheme).Build()
87+
},
88+
wantErr: require.NoError,
89+
want: func(t *testing.T, k8sClient client.Client) {
90+
el := tektoncd.NewEventListenerUnstructured()
91+
err := k8sClient.Get(context.Background(), client.ObjectKey{
92+
Namespace: "default",
93+
Name: generateEventListenerName("test-git-server"),
94+
}, el)
95+
require.Error(t, err)
96+
require.True(t, k8sErrors.IsNotFound(err))
97+
},
98+
},
4099
{
41100
name: "skip creating event listener because webhook URL is set",
42101
gitServer: &codebaseApi.GitServer{

deploy-templates/crds/v2.edp.epam.com_codebases.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ spec:
7373
ciTool:
7474
default: tekton
7575
description: A name of tool which should be used as CI.
76+
enum:
77+
- tekton
78+
- gitlab
7679
type: string
7780
cloneRepositoryCredentials:
7881
description: CloneRepositoryCredentials contains reference to secret

deploy-templates/crds/v2.edp.epam.com_gitservers.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ spec:
9292
sshPort:
9393
format: int32
9494
type: integer
95+
tektonDisabled:
96+
description: |-
97+
TektonDisabled disables creation of Tekton EventListener and associated
98+
Ingress/Route resources for this GitServer.
99+
Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions)
100+
is used instead of Tekton, or when webhook endpoints are managed externally.
101+
type: boolean
95102
webhookUrl:
96103
description: |-
97104
WebhookUrl is a URL for webhook that will be created in the git provider.

0 commit comments

Comments
 (0)