diff --git a/api/v1/codebase_types.go b/api/v1/codebase_types.go index 72e42556..b48baf0e 100644 --- a/api/v1/codebase_types.go +++ b/api/v1/codebase_types.go @@ -105,6 +105,7 @@ type CodebaseSpec struct { // A name of tool which should be used as CI. // +optional + // +kubebuilder:validation:Enum=tekton;gitlab // +kubebuilder:default:=tekton CiTool string `json:"ciTool"` diff --git a/api/v1/git_server_types.go b/api/v1/git_server_types.go index ad6a159f..379d942d 100644 --- a/api/v1/git_server_types.go +++ b/api/v1/git_server_types.go @@ -51,6 +51,13 @@ type GitServerSpec struct { // +optional // +kubebuilder:example:=`https://webhook-url.com` WebhookUrl string `json:"webhookUrl,omitempty"` + + // TektonDisabled disables creation of Tekton EventListener and associated + // Ingress/Route resources for this GitServer. + // Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions) + // is used instead of Tekton, or when webhook endpoints are managed externally. + // +optional + TektonDisabled bool `json:"tektonDisabled,omitempty"` } // GitServerStatus defines the observed state of GitServer. diff --git a/config/crd/bases/v2.edp.epam.com_codebases.yaml b/config/crd/bases/v2.edp.epam.com_codebases.yaml index bf56fb48..a6ea3d5d 100644 --- a/config/crd/bases/v2.edp.epam.com_codebases.yaml +++ b/config/crd/bases/v2.edp.epam.com_codebases.yaml @@ -73,6 +73,9 @@ spec: ciTool: default: tekton description: A name of tool which should be used as CI. + enum: + - tekton + - gitlab type: string cloneRepositoryCredentials: description: CloneRepositoryCredentials contains reference to secret diff --git a/config/crd/bases/v2.edp.epam.com_gitservers.yaml b/config/crd/bases/v2.edp.epam.com_gitservers.yaml index 18d40313..29d179fc 100644 --- a/config/crd/bases/v2.edp.epam.com_gitservers.yaml +++ b/config/crd/bases/v2.edp.epam.com_gitservers.yaml @@ -92,6 +92,13 @@ spec: sshPort: format: int32 type: integer + tektonDisabled: + description: |- + TektonDisabled disables creation of Tekton EventListener and associated + Ingress/Route resources for this GitServer. + Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions) + is used instead of Tekton, or when webhook endpoints are managed externally. + type: boolean webhookUrl: description: |- WebhookUrl is a URL for webhook that will be created in the git provider. diff --git a/controllers/codebasebranch/codebasebranch_controller.go b/controllers/codebasebranch/codebasebranch_controller.go index bc25e434..f0bbd6b6 100644 --- a/controllers/codebasebranch/codebasebranch_controller.go +++ b/controllers/codebasebranch/codebasebranch_controller.go @@ -331,6 +331,12 @@ func (r *ReconcileCodebaseBranch) setDefaultValues( return false, nil } + // GitLab CI codebases use .gitlab-ci.yml for pipeline configuration, + // so there is no need to generate Tekton pipeline names. + if codebase.Spec.CiTool == util.CIGitLab { + return false, nil + } + gitServer := &codebaseApi.GitServer{} if err := r.client.Get(ctx, types.NamespacedName{ Name: codebase.Spec.GitServer, diff --git a/controllers/codebasebranch/codebasebranch_controller_test.go b/controllers/codebasebranch/codebasebranch_controller_test.go index 66cfb73a..fdf6efc8 100644 --- a/controllers/codebasebranch/codebasebranch_controller_test.go +++ b/controllers/codebasebranch/codebasebranch_controller_test.go @@ -534,6 +534,7 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldSetPipelines(t *testing.T) { BuildTool: "go", Type: "application", GitServer: "test-gs", + CiTool: util.CITekton, Versioning: codebaseApi.Versioning{ Type: codebaseApi.VersioningTypDefault, }, @@ -609,6 +610,7 @@ func TestReconcileCodebaseBranch_Reconcile_FailedToSetPipelines_GitServerNotFoun BuildTool: "go", Type: "application", GitServer: "test-gs", + CiTool: util.CITekton, Versioning: codebaseApi.Versioning{ Type: codebaseApi.VersioningTypDefault, }, @@ -634,3 +636,108 @@ func TestReconcileCodebaseBranch_Reconcile_FailedToSetPipelines_GitServerNotFoun require.Error(t, err) require.Contains(t, err.Error(), "failed to get GitServer") } + +func TestReconcileCodebaseBranch_Reconcile_ShouldSkipPipelinesForGitLab(t *testing.T) { + cb := &codebaseApi.CodebaseBranch{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "test-branch", + Namespace: "default", + }, + Spec: codebaseApi.CodebaseBranchSpec{ + CodebaseName: "test-codebase", + BranchName: "test-branch", + }, + } + c := &codebaseApi.Codebase{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "test-codebase", + Namespace: "default", + }, + Spec: codebaseApi.CodebaseSpec{ + Lang: "go", + Framework: "gin", + BuildTool: "go", + Type: "application", + GitServer: "test-gs", + CiTool: util.CIGitLab, + Versioning: codebaseApi.Versioning{ + Type: codebaseApi.VersioningTypDefault, + }, + }, + } + gs := &codebaseApi.GitServer{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "test-gs", + Namespace: "default", + }, + Spec: codebaseApi.GitServerSpec{ + GitProvider: codebaseApi.GitProviderGithub, + }, + } + + scheme := runtime.NewScheme() + require.NoError(t, codebaseApi.AddToScheme(scheme)) + + fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb, gs).WithStatusSubresource(cb).Build() + + req := reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: "test-branch", + Namespace: "default", + }, + } + + controller := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard()) + + _, err := controller.Reconcile(context.Background(), req) + + require.NoError(t, err) + + updatedCb := &codebaseApi.CodebaseBranch{} + err = fakeCl.Get( + context.Background(), + types.NamespacedName{ + Name: "test-branch", + Namespace: "default", + }, + updatedCb, + ) + + require.NoError(t, err) + assert.Nil(t, updatedCb.Spec.Pipelines) +} + +func TestSetDefaultValues_ShouldSkipForGitLab(t *testing.T) { + cb := &codebaseApi.CodebaseBranch{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "test-branch", + Namespace: "default", + }, + Spec: codebaseApi.CodebaseBranchSpec{ + CodebaseName: "test-codebase", + BranchName: "test-branch", + }, + } + c := &codebaseApi.Codebase{ + ObjectMeta: metaV1.ObjectMeta{ + Name: "test-codebase", + Namespace: "default", + }, + Spec: codebaseApi.CodebaseSpec{ + CiTool: util.CIGitLab, + }, + } + + scheme := runtime.NewScheme() + require.NoError(t, codebaseApi.AddToScheme(scheme)) + + fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb).Build() + + r := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard()) + + changed, err := r.setDefaultValues(context.Background(), cb, c) + + require.NoError(t, err) + assert.False(t, changed) + assert.Nil(t, cb.Spec.Pipelines) +} diff --git a/controllers/gitserver/create_event_listener.go b/controllers/gitserver/create_event_listener.go index 0ad78830..1029bfbc 100644 --- a/controllers/gitserver/create_event_listener.go +++ b/controllers/gitserver/create_event_listener.go @@ -30,6 +30,11 @@ func NewCreateEventListener(k8sClient client.Client) *CreateEventListener { func (h *CreateEventListener) ServeRequest(ctx context.Context, gitServer *codebaseApi.GitServer) error { log := ctrl.LoggerFrom(ctx) + if gitServer.Spec.TektonDisabled { + log.Info("Skip creating EventListener because Tekton is disabled") + return nil + } + if gitServer.Spec.WebhookUrl != "" { log.Info("Skip creating EventListener because webhook URL is set") return nil @@ -53,7 +58,7 @@ func (h *CreateEventListener) createEventListener(ctx context.Context, gitServer // Use Unstructured to avoid direct dependency on "knative.dev/pkg/apis/duck/v1" because EventListener relies on it. // This dependency can conflict with the operator's dependencies. - // https://github.com/tektoncd/triggers/blob/v0.27.0/pkg/apis/triggers/v1beta1/event_listener_types.go#L86 + // https://github.com/tektoncd/triggers/blob/v0.34.0/pkg/apis/triggers/v1beta1/event_listener_types.go#L86 el := tektoncd.NewEventListenerUnstructured() elName := generateEventListenerName(gitServer.Name) diff --git a/controllers/gitserver/create_event_listener_test.go b/controllers/gitserver/create_event_listener_test.go index 26e6f749..231b780b 100644 --- a/controllers/gitserver/create_event_listener_test.go +++ b/controllers/gitserver/create_event_listener_test.go @@ -37,6 +37,65 @@ func TestCreateEventListener_ServeRequest(t *testing.T) { wantErr require.ErrorAssertionFunc want func(t *testing.T, k8sClient client.Client) }{ + { + name: "skip creating event listener because tekton is disabled", + gitServer: &codebaseApi.GitServer{ + ObjectMeta: controllerruntime.ObjectMeta{ + Name: "test-git-server", + Namespace: "default", + }, + Spec: codebaseApi.GitServerSpec{ + TektonDisabled: true, + }, + }, + k8sClient: func(t *testing.T) client.Client { + return fake.NewClientBuilder().WithScheme(scheme).Build() + }, + wantErr: require.NoError, + want: func(t *testing.T, k8sClient client.Client) { + el := tektoncd.NewEventListenerUnstructured() + err := k8sClient.Get(context.Background(), client.ObjectKey{ + Namespace: "default", + Name: generateEventListenerName("test-git-server"), + }, el) + require.Error(t, err) + require.True(t, k8sErrors.IsNotFound(err)) + + i := &networkingv1.Ingress{} + err = k8sClient.Get(context.Background(), client.ObjectKey{ + Namespace: "default", + Name: GenerateIngressName("test-git-server"), + }, i) + require.Error(t, err) + require.True(t, k8sErrors.IsNotFound(err)) + }, + }, + { + name: "skip creating event listener because tekton is disabled even with webhook URL set", + gitServer: &codebaseApi.GitServer{ + ObjectMeta: controllerruntime.ObjectMeta{ + Name: "test-git-server", + Namespace: "default", + }, + Spec: codebaseApi.GitServerSpec{ + TektonDisabled: true, + WebhookUrl: "https://external-webhook", + }, + }, + k8sClient: func(t *testing.T) client.Client { + return fake.NewClientBuilder().WithScheme(scheme).Build() + }, + wantErr: require.NoError, + want: func(t *testing.T, k8sClient client.Client) { + el := tektoncd.NewEventListenerUnstructured() + err := k8sClient.Get(context.Background(), client.ObjectKey{ + Namespace: "default", + Name: generateEventListenerName("test-git-server"), + }, el) + require.Error(t, err) + require.True(t, k8sErrors.IsNotFound(err)) + }, + }, { name: "skip creating event listener because webhook URL is set", gitServer: &codebaseApi.GitServer{ diff --git a/deploy-templates/crds/v2.edp.epam.com_codebases.yaml b/deploy-templates/crds/v2.edp.epam.com_codebases.yaml index bf56fb48..a6ea3d5d 100644 --- a/deploy-templates/crds/v2.edp.epam.com_codebases.yaml +++ b/deploy-templates/crds/v2.edp.epam.com_codebases.yaml @@ -73,6 +73,9 @@ spec: ciTool: default: tekton description: A name of tool which should be used as CI. + enum: + - tekton + - gitlab type: string cloneRepositoryCredentials: description: CloneRepositoryCredentials contains reference to secret diff --git a/deploy-templates/crds/v2.edp.epam.com_gitservers.yaml b/deploy-templates/crds/v2.edp.epam.com_gitservers.yaml index 18d40313..29d179fc 100644 --- a/deploy-templates/crds/v2.edp.epam.com_gitservers.yaml +++ b/deploy-templates/crds/v2.edp.epam.com_gitservers.yaml @@ -92,6 +92,13 @@ spec: sshPort: format: int32 type: integer + tektonDisabled: + description: |- + TektonDisabled disables creation of Tekton EventListener and associated + Ingress/Route resources for this GitServer. + Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions) + is used instead of Tekton, or when webhook endpoints are managed externally. + type: boolean webhookUrl: description: |- WebhookUrl is a URL for webhook that will be created in the git provider. diff --git a/docs/api.md b/docs/api.md index f1b63b13..0323efcb 100644 --- a/docs/api.md +++ b/docs/api.md @@ -796,10 +796,11 @@ Selected branch will become a default branch for a new codebase (e.g. master, ma false ciTool - string + enum A name of tool which should be used as CI.

+ Enum: tekton, gitlab
Default: tekton
false @@ -1276,6 +1277,16 @@ For Gerrit provider, only id_rsa key is required and used.
SkipWebhookSSLVerification is a flag to skip webhook tls verification.
false + + tektonDisabled + boolean + + TektonDisabled disables creation of Tekton EventListener and associated +Ingress/Route resources for this GitServer. +Use this when the git provider's native CI (e.g. GitLab CI, GitHub Actions) +is used instead of Tekton, or when webhook endpoints are managed externally.
+ + false webhookUrl string diff --git a/pkg/tektoncd/triggers.go b/pkg/tektoncd/triggers.go index 0e70309d..7c653f75 100644 --- a/pkg/tektoncd/triggers.go +++ b/pkg/tektoncd/triggers.go @@ -7,7 +7,7 @@ import ( const ( triggersGroup = "triggers.tekton.dev" - triggersAPIVersion = "v1alpha1" + triggersAPIVersion = "v1beta1" triggersKind = "EventListener" )