blob: e88271afd7cf2e6bbc373545603408a927e8ff87 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
# Configures the shell for recipes to use bash, enabling bash commands and ensuring
# that recipes exit on any command failure (including within pipes).
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
## Variables
BUILD_IMAGE ?= true
DOCKER ?= docker
MINIKUBE_PROFILE ?= minikube
DEPENDENCIES ?= ct helm helm-docs java21 git
OPTIONAL_DEPENDENCIES := jq kubectl minikube
VENV_DIR := .venv
PYTHON_CLIENT_DIR := client/python
ACTIVATE_AND_CD = source $(VENV_DIR)/bin/activate && cd $(PYTHON_CLIENT_DIR)
## Version information
BUILD_VERSION := $(shell cat version.txt)
GIT_COMMIT := $(shell git rev-parse HEAD)
POETRY_VERSION := $(shell cat client/python/pyproject.toml | grep requires-poetry | sed 's/requires-poetry *= *"\(.*\)"/\1/')
##@ General
.PHONY: help
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9\.-]+:.*?##/ { printf " \033[36m%-40s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
.PHONY: version
version: ## Display version information
@echo "Build version: ${BUILD_VERSION}"
@echo "Git commit: ${GIT_COMMIT}"
@echo "Poetry version: ${POETRY_VERSION}"
##@ Polaris Build
.PHONY: build
build: build-server build-admin ## Build Polaris server, admin, and container images
build-server: DEPENDENCIES := java21 $(DOCKER)
.PHONY: build-server
build-server: check-dependencies ## Build Polaris server and container image
@echo "--- Building Polaris server ---"
@./gradlew \
:polaris-server:assemble \
:polaris-server:quarkusAppPartsBuild --rerun \
-Dquarkus.container-image.build=$(BUILD_IMAGE) \
-Dquarkus.docker.executable-name=$(DOCKER)
@echo "--- Polaris server build complete ---"
build-admin: DEPENDENCIES := java21 $(DOCKER)
.PHONY: build-admin
build-admin: check-dependencies ## Build Polaris admin and container image
@echo "--- Building Polaris admin ---"
@./gradlew \
:polaris-admin:assemble \
:polaris-admin:quarkusAppPartsBuild --rerun \
-Dquarkus.container-image.build=$(BUILD_IMAGE) \
-Dquarkus.docker.executable-name=$(DOCKER)
@echo "--- Polaris admin build complete ---"
build-spark-plugin-3.5-2.12: DEPENDENCIES := java21
.PHONY: build-spark-plugin-3.5-2.12
build-spark-plugin-3.5-2.12: check-dependencies ## Build Spark plugin v3.5 with Scala v2.12
@echo "--- Building Spark plugin v3.5 with Scala v2.12 ---"
@./gradlew \
:polaris-spark-3.5_2.12:assemble
@echo "--- Spark plugin v3.5 with Scala v2.12 build complete ---"
build-spark-plugin-3.5-2.13: DEPENDENCIES := java21
.PHONY: build-spark-plugin-3.5-2.13
build-spark-plugin-3.5-2.13: check-dependencies ## Build Spark plugin v3.5 with Scala v2.13
@echo "--- Building Spark plugin v3.5 with Scala v2.13 ---"
@./gradlew \
:polaris-spark-3.5_2.13:assemble
@echo "--- Spark plugin v3.5 with Scala v2.13 build complete ---"
build-cleanup: DEPENDENCIES := java21
.PHONY: build-cleanup
build-cleanup: check-dependencies ## Clean build artifacts
@echo "--- Cleaning up build artifacts ---"
@./gradlew clean
@echo "--- Build artifacts cleaned ---"
spotless-apply: DEPENDENCIES := java21
.PHONY: spotless-apply
spotless-apply: check-dependencies ## Apply code formatting using Spotless Gradle plugin.
@echo "--- Applying Spotless formatting ---"
@./gradlew spotlessApply
@echo "--- Spotless formatting applied ---"
##@ Polaris Client
# Target to create the virtual environment directory
$(VENV_DIR):
@echo "Setting up Python virtual environment at $(VENV_DIR)..."
@python3 -m venv $(VENV_DIR)
@echo "Virtual environment created."
.PHONY: client-install-dependencies
client-install-dependencies: $(VENV_DIR)
@echo "Installing Poetry and project dependencies into $(VENV_DIR)..."
@$(VENV_DIR)/bin/pip install --upgrade pip
@if [ ! -f "$(VENV_DIR)/bin/poetry" ]; then \
$(VENV_DIR)/bin/pip install --upgrade "poetry$(POETRY_VERSION)"; \
fi
@$(ACTIVATE_AND_CD) && poetry install --all-extras
@echo "Poetry and dependencies installed."
.PHONY: client-setup-env
client-setup-env: $(VENV_DIR) client-install-dependencies
.PHONY: client-lint
client-lint: client-setup-env ## Run linting checks for Polaris client
@echo "--- Running client linting checks ---"
@$(ACTIVATE_AND_CD) && poetry run pre-commit run --files integration_tests/* python/cli/*
@echo "--- Client linting checks complete ---"
.PHONY: client-regenerate
client-regenerate: client-setup-env ## Regenerate the client code
@echo "--- Regenerating client code ---"
@$(ACTIVATE_AND_CD) && python3 -B generate_clients.py
@echo "--- Client code regeneration complete ---"
.PHONY: client-unit-test
client-unit-test: client-setup-env ## Run client unit tests
@echo "--- Running client unit tests ---"
@$(ACTIVATE_AND_CD) && poetry run pytest test/
@echo "--- Client unit tests complete ---"
.PHONY: client-integration-test
client-integration-test: build-server client-setup-env ## Run client integration tests
@echo "--- Starting client integration tests ---"
@echo "Ensuring Docker Compose services are stopped and removed..."
@$(DOCKER) compose -f $(PYTHON_CLIENT_DIR)/docker-compose.yml kill || true # `|| true` prevents make from failing if containers don't exist
@$(DOCKER) compose -f $(PYTHON_CLIENT_DIR)/docker-compose.yml rm -f || true # `|| true` prevents make from failing if containers don't exist
@echo "Bringing up Docker Compose services in detached mode..."
@$(DOCKER) compose -f $(PYTHON_CLIENT_DIR)/docker-compose.yml up -d
@echo "Waiting for Polaris HTTP health check to pass..."
@until curl -s -f http://localhost:8182/q/health > /dev/null; do \
echo "Still waiting for HTTP 200 from /q/health (sleeping 2s)..."; \
sleep 2; \
done
@echo "Polaris is healthy. Starting integration tests..."
@$(ACTIVATE_AND_CD) && poetry run pytest integration_tests/
@echo "--- Client integration tests complete ---"
@echo "Tearing down Docker Compose services..."
@$(DOCKER) compose -f $(PYTHON_CLIENT_DIR)/docker-compose.yml down || true # Ensure teardown even if tests fail
.PHONY: client-license-check
client-license-check: client-setup-env ## Run license compliance check
@echo "--- Starting license compliance check ---"
@$(ACTIVATE_AND_CD) && pip-licenses
@echo "--- License compliance check complete ---"
.PHONY: client-build
client-build: client-setup-env ## Build client distribution. Pass FORMAT=sdist or FORMAT=wheel to build a specific format.
@echo "--- Building client distribution ---"
@if [ -n "$(FORMAT)" ]; then \
if [ "$(FORMAT)" != "sdist" ] && [ "$(FORMAT)" != "wheel" ]; then \
echo "Error: Invalid format '$(FORMAT)'. Supported formats are 'sdist' and 'wheel'." >&2; \
exit 1; \
fi; \
echo "Building with format: $(FORMAT)"; \
$(ACTIVATE_AND_CD) && poetry build --format $(FORMAT); \
else \
echo "Building default distribution (sdist and wheel)"; \
$(ACTIVATE_AND_CD) && poetry build; \
fi
@echo "--- Client distribution build complete ---"
.PHONY: client-cleanup
client-cleanup: ## Cleanup virtual environment and Python cache files
@echo "--- Cleaning up virtual environment and Python cache files ---"
@echo "Attempting to remove virtual environment directory: $(VENV_DIR)..."
@if [ -n "$(VENV_DIR)" ] && [ -d "$(VENV_DIR)" ]; then \
rm -rf "$(VENV_DIR)"; \
echo "Virtual environment removed."; \
else \
echo "Virtual environment directory '$(VENV_DIR)' not found or VENV_DIR is empty. No action taken."; \
fi
@echo "Cleaning up Python cache files..."
@find $(PYTHON_CLIENT_DIR) -type f -name "*.pyc" -delete
@find $(PYTHON_CLIENT_DIR) -type d -name "__pycache__" -delete
@echo "--- Virtual environment and Python cache cleanup complete ---"
##@ Helm
helm-doc-generate: DEPENDENCIES := helm-docs
.PHONY: helm-doc-generate
helm-doc-generate: check-dependencies ## Generate Helm chart documentation
@echo "--- Generating Helm documentation ---"
@helm-docs --chart-search-root=helm
@cp helm/polaris/README.md site/content/in-dev/unreleased/helm.md
@echo "--- Helm documentation generated and copied ---"
helm-unittest: DEPENDENCIES := helm
.PHONY: helm-unittest
helm-unittest: check-dependencies ## Run Helm chart unittest
@echo "--- Running Helm chart unittest ---"
@helm unittest helm/polaris
@echo "--- Helm chart unittest complete ---"
helm-lint: DEPENDENCIES := ct
.PHONY: helm-lint
helm-lint: check-dependencies ## Run Helm chart lint check
@echo "--- Running Helm chart linting ---"
@ct lint --charts helm/polaris
@echo "--- Helm chart linting complete ---"
##@ Minikube
minikube-start-cluster: DEPENDENCIES := minikube $(DOCKER)
.PHONY: minikube-start-cluster
minikube-start-cluster: check-dependencies ## Start the Minikube cluster
@echo "--- Checking Minikube cluster status ---"
@if minikube status -p $(MINIKUBE_PROFILE) --format "{{.Host}}" | grep -q "Running"; then \
echo "--- Minikube cluster is already running. Skipping start ---"; \
else \
echo "--- Starting Minikube cluster ---"; \
if [ "$(DOCKER)" = "podman" ]; then \
minikube start -p $(MINIKUBE_PROFILE) --driver=$(DOCKER) --container-runtime=cri-o; \
else \
minikube start -p $(MINIKUBE_PROFILE) --driver=$(DOCKER); \
fi; \
echo "--- Minikube cluster started ---"; \
fi
minikube-stop-cluster: DEPENDENCIES := minikube $(DOCKER)
.PHONY: minikube-stop-cluster
minikube-stop-cluster: check-dependencies ## Stop the Minikube cluster
@echo "--- Checking Minikube cluster status ---"
@if minikube status -p $(MINIKUBE_PROFILE) --format "{{.Host}}" | grep -q "Running"; then \
echo "--- Stopping Minikube cluster ---"; \
minikube stop -p $(MINIKUBE_PROFILE); \
echo "--- Minikube cluster stopped ---"; \
else \
echo "--- Minikube cluster is already stopped or does not exist. Skipping stop ---"; \
fi
minikube-load-images: DEPENDENCIES := minikube $(DOCKER)
.PHONY: minikube-load-images
minikube-load-images: minikube-start-cluster check-dependencies ## Load local Docker images into the Minikube cluster
@echo "--- Loading images into Minikube cluster ---"
@minikube image load -p $(MINIKUBE_PROFILE) docker.io/apache/polaris:latest
@minikube image tag -p $(MINIKUBE_PROFILE) docker.io/apache/polaris:latest docker.io/apache/polaris:$(BUILD_VERSION)
@minikube image load -p $(MINIKUBE_PROFILE) docker.io/apache/polaris-admin-tool:latest
@minikube image tag -p $(MINIKUBE_PROFILE) docker.io/apache/polaris-admin-tool:latest docker.io/apache/polaris-admin-tool:$(BUILD_VERSION)
@echo "--- Images loaded into Minikube cluster ---"
minikube-cleanup: DEPENDENCIES := minikube $(DOCKER)
.PHONY: minikube-cleanup
minikube-cleanup: check-dependencies ## Cleanup the Minikube cluster
@echo "--- Checking Minikube cluster status ---"
@if minikube status -p $(MINIKUBE_PROFILE) >/dev/null 2>&1; then \
echo "--- Cleanup Minikube cluster ---"; \
minikube delete -p $(MINIKUBE_PROFILE); \
echo "--- Minikube cluster removed ---"; \
else \
echo "--- Minikube cluster does not exist. Skipping cleanup ---"; \
fi
##@ Pre-commit
.PHONY: pre-commit
pre-commit: spotless-apply helm-doc-generate client-lint ## Run tasks for pre-commit
##@ Dependencies
.PHONY: check-dependencies
check-dependencies: ## Check if all requested dependencies are present
@echo "--- Checking for requested dependencies ---"
@for dependency in $(DEPENDENCIES); do \
echo "Checking for $$dependency..."; \
if [ "$$dependency" = "java21" ]; then \
if java --version | head -n1 | cut -d' ' -f2 | grep -q '^21\.'; then \
echo "Java 21 is installed."; \
else \
echo "Java 21 is NOT installed."; \
echo "--- ERROR: Dependency 'Java 21' is missing. Please install it to proceed. Exiting. ---"; \
exit 1; \
fi ; \
elif command -v $$dependency >/dev/null 2>&1; then \
echo "$$dependency is installed."; \
else \
echo "$$dependency is NOT installed."; \
echo "--- ERROR: Dependency '$$dependency' is missing. Please install it to proceed. Exiting. ---"; \
exit 1; \
fi; \
done
@echo "--- All checks complete. ---"
.PHONY: check-brew
check-brew:
@echo "--- Checking Homebrew installation ---"
@if command -v brew >/dev/null 2>&1; then \
echo "--- Homebrew is installed ---"; \
else \
echo "--- Homebrew is not installed. Aborting ---"; \
exit 1; \
fi
.PHONY: install-dependencies-brew
install-dependencies-brew: check-brew ## Install dependencies if not present via Brew
@echo "--- Checking and installing dependencies for this target ---"
@for dependency in $(DEPENDENCIES); do \
case $$dependency in \
java21) \
if java -version 2>&1 | grep -q '21'; then \
:; \
else \
echo "Java 21 is not installed. Installing openjdk@21 and jenv..."; \
brew install openjdk@21 jenv; \
$(shell brew --prefix jenv)/bin/jenv add $(shell brew --prefix openjdk@21); \
jenv local 21; \
echo "Java 21 installed."; \
fi ;; \
docker|podman) \
if command -v $$dependency >/dev/null 2>&1; then \
:; \
else \
echo "$$dependency is not installed. Manual installation required"; \
fi ;; \
ct) \
if command -v ct >/dev/null 2>&1; then \
:; \
else \
echo "ct is not installed. Installing with Homebrew..."; \
brew install chart-testing; \
echo "ct installed."; \
fi ;; \
*) \
if command -v $$dependency >/dev/null 2>&1; then \
:; \
else \
echo "$$dependency is not installed. Installing with Homebrew..."; \
brew install $$dependency; \
echo "$$dependency installed."; \
fi ;; \
esac; \
done
@echo "--- All requested dependencies checked/installed ---"
install-optional-dependencies-brew: DEPENDENCIES := $(OPTIONAL_DEPENDENCIES)
.PHONY: install-optional-dependencies-brew
install-optional-dependencies-brew: install-dependencies-brew ## Install optional dependencies if not present via Brew