diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 9defe3970..1acc2e9a5 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -16,7 +16,7 @@ env: GO_VERSION: 1.22 PYTHON_VERSION: "3.10" KIND_VERSION: v0.20.0 - KNATIVE_VERSION: v1.13.2 + KNATIVE_VERSION: v1.12.5 OPERATOR_IMAGE_NAME: "127.0.0.1:5001/kogito-serverless-operator:0.0.1" jobs: @@ -84,28 +84,19 @@ jobs: make deploy IMG=${{ env.OPERATOR_IMAGE_NAME }} kubectl wait pod -A -l control-plane=sonataflow-operator --for condition=Ready - - name: Run tests for workflows without persistence + - name: [Ephemeral Workflows] Run e2e tests run: make test-e2e label=flows-non-persistence - - name: Retrieve cluster events and list pods - if: failure() - run: | - kubectl get events - kubectl get pod -A - - - name: Run tests for workflows with persistence + - name: [Persistence Workflows] Run e2e tests run: make test-e2e label=flows-persistence - - name: Retrieve cluster events and list pods - if: failure() - run: | - kubectl get events - kubectl get pod -A - - - name: Run tests for platform use cases + - name: [Platform] Run e2e tests run: make test-e2e label=platform - - name: Retrieve cluster events and list pods + - name: [Cluster Platform] Run e2e tests + run: make test-e2e label=cluster + + - name: Get KIND logs after failure run if: failure() run: | kubectl get events @@ -119,7 +110,7 @@ jobs: - name: Upload kind logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }} path: /tmp/kind/logs diff --git a/Makefile b/Makefile index 0e4bc7d14..71c9823d6 100644 --- a/Makefile +++ b/Makefile @@ -96,30 +96,40 @@ help: ## Display this help. .PHONY: manifests manifests: generate ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd:allowDangerousTypes=true webhook paths="./api/..." paths="./internal/controller/..." output:crd:artifacts:config=config/crd/bases + @echo "๐Ÿ“„ Generating WebhookConfiguration, ClusterRole, and CRD objects..." + @$(CONTROLLER_GEN) rbac:roleName=manager-role crd:allowDangerousTypes=true webhook paths="./api/..." paths="./internal/controller/..." output:crd:artifacts:config=config/crd/bases > /dev/null 2>&1 .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. - $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/..." paths="./container-builder/api/..." + @echo "๐Ÿ”„ Generating DeepCopy methods for APIs..." + @$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/..." paths="./container-builder/api/..." > /dev/null 2>&1 .PHONY: fmt fmt: ## Run go fmt against code. - ./hack/goimports.sh - go work sync - go mod tidy - go fmt ./... + @echo "๐Ÿงน Running go fmt and goimports..." + @./hack/goimports.sh > /dev/null 2>&1 + @go work sync > /dev/null 2>&1 + @go mod tidy > /dev/null 2>&1 + @go fmt ./... > /dev/null 2>&1 .PHONY: vet vet: ## Run go vet against code. - go vet ./... + @echo "๐Ÿ” Running go vet..." + @go vet ./... > /dev/null 2>&1 .PHONY: test -test: manifests generate envtest vet fmt test-api ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $(shell go list ./... | grep -v /test/) -coverprofile cover.out +test: manifests generate envtest test-api ## Run tests. + @echo "๐Ÿ” Running controller tests..." + @KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" \ + go test $(shell go list ./... | grep -v /test/) -coverprofile cover.out > /dev/null 2>&1 + @echo "โœ… Tests completed successfully. Coverage report generated: cover.out." .PHONY: test-api test-api: - cd api && make test + @echo "๐Ÿ”„ Running API tests..." + @cd api && make test > /dev/null 2>&1 + @echo "โœ… API tests completed successfully." + .PHONY: lint lint: golangci-lint ## Run golangci-lint linter @@ -218,8 +228,11 @@ deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in .PHONY: generate-deploy generate-deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default > operator.yaml + @echo "๐Ÿš€ Updating controller image to ${IMG}..." + @cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} > /dev/null 2>&1 + @echo "๐Ÿ“„ Building deployment YAML..." + @$(KUSTOMIZE) build config/default > operator.yaml + .PHONY: undeploy undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. @@ -260,8 +273,8 @@ $(KUSTOMIZE): $(LOCALBIN) .PHONY: controller-gen controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. -$(CONTROLLER_GEN): $(LOCALBIN) - test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + @echo "โฌ‡๏ธ Ensuring controller-gen is installed..." + @test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) > /dev/null 2>&1 .PHONY: envtest envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. @@ -290,10 +303,14 @@ endef .PHONY: bundle bundle: manifests kustomize install-operator-sdk ## Generate bundle manifests and metadata, then validate generated files. - operator-sdk generate kustomize manifests -q - cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) - operator-sdk bundle validate ./bundle + @echo "๐Ÿ“ฆ Generating bundle manifests and metadata..." + @operator-sdk generate kustomize manifests -q > /dev/null 2>&1 + @echo "๐Ÿ”ง Setting controller image in Kustomize..." + @cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) > /dev/null 2>&1 + @echo "๐Ÿ”จ Building Kustomize and generating bundle..." + @$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) > /dev/null 2>&1 + @echo "๐Ÿ› ๏ธ Validating generated bundle..." + @operator-sdk bundle validate ./bundle > /dev/null 2>&1 .PHONY: bundle-build bundle-build: ## Build the bundle image @@ -361,25 +378,54 @@ snapshot = "" bump-version: ./hack/bump-version.sh $(new_version) $(snapshot) +.PHONY: install-operator-sdk install-operator-sdk: - ./hack/install-operator-sdk.sh + @echo "๐Ÿ“ฆ Installing Operator SDK..." + @./hack/install-operator-sdk.sh > /dev/null 2>&1 + .PHONY: addheaders addheaders: - ./hack/addheaders.sh + @echo "๐Ÿ“ Adding headers to files..." + @./hack/addheaders.sh > /dev/null 2>&1 .PHONY: generate-all -generate-all: generate generate-deploy bundle addheaders vet fmt +generate-all: generate generate-deploy bundle + @$(MAKE) addheaders + @$(MAKE) vet + @$(MAKE) fmt -.PHONY: test-e2e # You will need to have a Minikube/Kind cluster up in running to run this target, and run container-builder before the test -label = "flows-non-persistence" # possible values are flows-non-persistence, flows-persistence, platform +.PHONY: test-e2e # You will need to have a Minikube/Kind cluster up and running to run this target, and run container-builder before the test +label = "flows-non-persistence" # possible values are flows-non-persistence, flows-persistence, platform, cluster test-e2e: - go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/clusterplatform_test.go -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) -ginkgo.junit-report=./e2e-test-report-clusterplatform_test.xml -timeout 60m; - go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/platform_test.go -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) -ginkgo.junit-report=./e2e-test-report-platform_test.xml -timeout 60m; - go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/workflow_test.go -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) -ginkgo.junit-report=./e2e-test-report-workflow_test.xml -timeout 60m; +ifeq ($(label), cluster) + @echo "๐ŸŒ Running e2e tests for cluster..." + go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/clusterplatform_test.go \ + -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) \ + -ginkgo.junit-report=./e2e-test-report-clusterplatform_test.xml -timeout 60m; +else ifeq ($(label), platform) + @echo "๐Ÿ“ฆ Running e2e tests for platform..." + go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/platform_test.go \ + -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) \ + -ginkgo.junit-report=./e2e-test-report-platform_test.xml -timeout 60m; +else ifeq ($(label), flows-non-persistence) + @echo "๐Ÿ”„ Running e2e tests for flows-non-persistence..." + go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/workflow_test.go \ + -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) \ + -ginkgo.junit-report=./e2e-test-report-workflow_test.xml -timeout 60m; +else ifeq ($(label), flows-persistence) + @echo "๐Ÿ” Running e2e tests for flows-persistence..." + go test ./test/e2e/e2e_suite_test.go ./test/e2e/helpers.go ./test/e2e/workflow_test.go \ + -v -ginkgo.v -ginkgo.no-color -ginkgo.github-output -ginkgo.label-filter=$(label) \ + -ginkgo.junit-report=./e2e-test-report-workflow_test.xml -timeout 60m; +else + @echo "โŒ Invalid label. Please use one of: cluster, platform, flows-non-persistence, flows-persistence" +endif + .PHONY: before-pr -before-pr: test generate-all +before-pr: generate-all test ## Run generate-all before executing tests. + @echo "โœ… Your working branch is done." .PHONY: install-kind @@ -391,7 +437,7 @@ create-cluster: install-kind kind get clusters | grep kind >/dev/null || ./hack/ci/create-kind-cluster-with-registry.sh $(BUILDER) .PHONY: deploy-knative -deploy-knative: create-cluster +deploy-knative: kubectl apply -f https://github.com/knative/operator/releases/download/knative-$(KNATIVE_VERSION)/operator.yaml kubectl wait --for=condition=Available=True deploy/knative-operator -n default --timeout=$(TIMEOUT_SECS) kubectl apply -f ./test/testdata/knative_serving_eventing.yaml diff --git a/hack/local/run-e2e.sh b/hack/local/run-e2e.sh index 3261c0e0f..3515b6c0a 100755 --- a/hack/local/run-e2e.sh +++ b/hack/local/run-e2e.sh @@ -19,23 +19,51 @@ # runs the e2e locally # You must have minikube installed MINIKUBE_PROFILE=${1:-minikube} -SKIP_IMG_BUILD=${2:-0} -TEST_LABELS=${3:-"flows-non-persistence"} # possible values are flows-non-persistence, flows-persistence, platform +SKIP_IMG_BUILD=${2:-false} +TEST_LABELS=${3:-"flows-non-persistence"} # possible values are flows-non-persistence, flows-persistence, platform, cluster -echo "Using minikube profile ${MINIKUBE_PROFILE}" +# Emoticons and enhanced messages +echo "๐Ÿš€ Using minikube profile ${MINIKUBE_PROFILE}" export OPERATOR_IMAGE_NAME=localhost/kogito-serverless-operator:0.0.1 -# clean up previous runs -kubectl get namespaces -o name | awk -F/ '/^namespace\/test/ {print $2}' | xargs kubectl delete namespace -make undeploy ignore-not-found=true +# Check if the minikube registry addon is enabled +if ! minikube addons list | grep -q "registry.*enabled"; then + echo "๐Ÿ”Œ Enabling minikube registry addon..." + minikube addons enable registry +else + echo "โœ… Minikube registry addon is already enabled." +fi + +# clean up previous runs, hiding logs +echo "๐Ÿงน Cleaning up previous test namespaces..." +kubectl get namespaces -o name | awk -F/ '/^namespace\/test/ {print $2}' | xargs kubectl delete namespace &> /dev/null +echo "๐Ÿงน Undeploying previous instances..." +make undeploy ignore-not-found=true &> /dev/null -if [ "${SKIP_IMG_BUILD}" = true ]; then +# Image build process +if [ "${SKIP_IMG_BUILD}" = "false" ]; then + # Check if cekit is available + if ! command -v cekit &> /dev/null; then + echo "โŒ cekit command not found. Please install cekit before proceeding." >&2 + exit 1 + fi + echo "๐Ÿ“ฆ Installing required Python packages for cekit..." + if ! pip install -r ./images/requirements.txt &> /dev/null; then + echo "โŒ Failed to install required Python packages. Please check your requirements file." >&2 + exit 1 + fi + echo "๐Ÿ”จ Building operator image..." eval "$(minikube -p "${MINIKUBE_PROFILE}" docker-env)" - if ! make container-build BUILDER=docker IMG="${OPERATOR_IMAGE_NAME}"; then - echo "Failure: Failed to build image, exiting " >&2 + if ! make container-build BUILDER=docker IMG="${OPERATOR_IMAGE_NAME}" ; then + echo "โŒ Failure: Failed to build image, exiting." >&2 exit 1 fi +else + echo "โฉ Skipping operator image build..." fi -make deploy IMG="${OPERATOR_IMAGE_NAME}" +# Deploy and run tests, keeping logs visible for tests only +echo "๐Ÿš€ Deploying operator..." +make deploy IMG="${OPERATOR_IMAGE_NAME}" &> /dev/null +echo "๐Ÿงช Running e2e tests with label ${TEST_LABELS}..." make test-e2e label="${TEST_LABELS}" diff --git a/internal/controller/sonataflow_controller.go b/internal/controller/sonataflow_controller.go index 5eec3b69b..404e3ccf8 100644 --- a/internal/controller/sonataflow_controller.go +++ b/internal/controller/sonataflow_controller.go @@ -23,6 +23,10 @@ import ( "context" "fmt" + "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/knative" + sourcesv1 "knative.dev/eventing/pkg/apis/sources/v1" + servingv1 "knative.dev/serving/pkg/apis/serving/v1" + "k8s.io/klog/v2" "github.com/apache/incubator-kie-kogito-serverless-operator/api/metadata" @@ -39,8 +43,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" - sourcesv1 "knative.dev/eventing/pkg/apis/sources/v1" - servingv1 "knative.dev/serving/pkg/apis/serving/v1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -52,7 +54,6 @@ import ( "github.com/apache/incubator-kie-kogito-serverless-operator/log" operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08" - "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/knative" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/platform" ) diff --git a/internal/controller/sonataflowplatform_controller.go b/internal/controller/sonataflowplatform_controller.go index 449bdd5cd..b5fbbe269 100644 --- a/internal/controller/sonataflowplatform_controller.go +++ b/internal/controller/sonataflowplatform_controller.go @@ -24,13 +24,15 @@ import ( "fmt" "time" + "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/knative" + sourcesv1 "knative.dev/eventing/pkg/apis/sources/v1" + "k8s.io/klog/v2" "github.com/apache/incubator-kie-kogito-serverless-operator/api" operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08" clientr "github.com/apache/incubator-kie-kogito-serverless-operator/container-builder/client" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/clusterplatform" - "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/knative" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/platform" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/platform/services" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/profiles/common/constants" @@ -44,7 +46,6 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" - sourcesv1 "knative.dev/eventing/pkg/apis/sources/v1" ctrlrun "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ctrl "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/test/e2e/clusterplatform_test.go b/test/e2e/clusterplatform_test.go index 6f9d868a6..8602afab2 100644 --- a/test/e2e/clusterplatform_test.go +++ b/test/e2e/clusterplatform_test.go @@ -40,7 +40,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("Validate a clusterplatform", Ordered, func() { +var _ = Describe("Cluster Platform Use Cases :: ", Label("cluster"), Ordered, func() { var ( projectDir string diff --git a/test/e2e/platform_test.go b/test/e2e/platform_test.go index 2d4665839..d34e7cc79 100644 --- a/test/e2e/platform_test.go +++ b/test/e2e/platform_test.go @@ -40,7 +40,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("SonataFlow Operator :: Platform Use Cases :: ", Label("platform"), Ordered, func() { +var _ = Describe("Platform Use Cases :: ", Label("platform"), Ordered, func() { var ( projectDir string diff --git a/test/e2e/workflow_test.go b/test/e2e/workflow_test.go index 13cdb7a7a..9d7b5c93b 100644 --- a/test/e2e/workflow_test.go +++ b/test/e2e/workflow_test.go @@ -44,7 +44,7 @@ const ( workflowAppLabel = "sonataflow.org/workflow-app" ) -var _ = Describe("SonataFlow Operator :: Workflow Non-Persistence Use Cases :: ", Label("flows-non-persistence"), Ordered, func() { +var _ = Describe("Workflow Non-Persistence Use Cases :: ", Label("flows-non-persistence"), Ordered, func() { var targetNamespace string BeforeEach(func() { @@ -149,7 +149,7 @@ var _ = Describe("SonataFlow Operator :: Workflow Non-Persistence Use Cases :: " }) -var _ = Describe("SonataFlow Operator :: Workflow Persistence Use Cases :: ", Label("flows-persistence"), Ordered, func() { +var _ = Describe("Workflow Persistence Use Cases :: ", Label("flows-persistence"), Ordered, func() { const ( dbConnectionName = "Database connections health check"