# Makefile (enhanced) SHELL := /bin/sh .DEFAULT_GOAL := help # Docker Compose file COMPOSE_FILE := -f .dev/docker-compose.yml # Reusable vars DOCKER := docker compose $(COMPOSE_FILE) COMPOSER_RUNTIME := composer-runtime DEV_RUNTIME := dev-runtime MIGRATION_CONTAINER := migration-container PROTOC_GEN_DIR := ./protoc-gen-php-grpc-2025.1.5-darwin-arm64 PROTOC_GEN := $(PROTOC_GEN_DIR)/protoc-gen-php-grpc PROTOC_URL := https://github.com/roadrunner-server/roadrunner/releases/download/v2025.1.5/protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz DEV := $(DOCKER) exec $(DEV_RUNTIME) sh -c COMPOSER := $(DOCKER) exec $(COMPOSER_RUNTIME) sh -c # Colors GREEN := \033[32m YELLOW := \033[33m RESET := \033[0m # Fancy emoji SPARK := โœจ ROCKET := ๐Ÿš€ WARN := โš ๏ธ MAGNIFY := ๐Ÿ” BUG := ๐Ÿž COMPOSE := ๐Ÿณ TRASH := ๐Ÿงน PROTO := ๐Ÿงฉ CHECK := โœ… CROSS := โŒ # Align width for help display HELP_COL_WIDTH := 26 # Help: auto-generate from targets with "##" comments help: ## Show this help @echo "$(SPARK) Available commands:" @awk -F':|##' '/^[a-zA-Z0-9._-]+:.*##/ {printf " %-$(HELP_COL_WIDTH)s - %s\n", $$1, $$3}' $(MAKEFILE_LIST) | sort docker-build: ## Build Docker image @push_flag=""; \ if [ -n "$(push)" ]; then \ push="--push"; \ fi @if [ -z "$(image)" ]; then \ echo "image variable is required: make docker-build image=your-image-name tag=your"; \ exit 1; \ fi @if [ -z "$(tag)" ]; then \ echo "tag variable is required: make docker-build image=your-image-name tag=your"; \ exit 1; \ fi @platform_flag=""; \ if [ -n "$(platform)" ]; then \ platform_flag="--platform=$(platform)"; \ fi; \ printf "$(YELLOW)$(SPARK) Building Docker image: $(image):$(tag)$(RESET)\n"; \ docker buildx build $$platform_flag --provenance=true --sbom=true $$push_flag --tag $(image):$(tag) . start: ## Start the development runtime container @printf "$(GREEN)$(ROCKET) Starting $(DEV_RUNTIME)$(RESET)\n" $(DOCKER) up $(DEV_RUNTIME) -d --no-recreate sh: ## Open a shell in the development runtime container @$(MAKE) start $(DOCKER) exec $(DEV_RUNTIME) sh run: ## Run the application server in the development runtime container @$(MAKE) start $(DEV) "rr serve" stop: ## Stop and remove the development runtime container @printf "$(YELLOW)$(WARN) Stopping all containers$(RESET)\n" $(DOCKER) down restart: ## Restart dev container (stop + start) @$(MAKE) stop @$(MAKE) start rebuild: ## Rebuild containers (useful after Dockerfile changes) @printf "$(YELLOW)$(SPARK) Rebuilding containers$(RESET)\n" @$(MAKE) stop @printf "$(YELLOW)$(TRASH) Deleting all Docker resources$(RESET)\n" docker system prune --all --volumes --force @$(MAKE) start ps: ## Show docker compose ps $(DOCKER) ps migrate: ## Run database migrations in the migration container $(DOCKER) up $(MIGRATION_CONTAINER) # Composer helpers composer-install: ## Install PHP dependencies in the composer runtime container @printf "$(COMPOSE) $(GREEN)Installing PHP dependencies in $(COMPOSER_RUNTIME)$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer install --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs" composer-install-no-dev: ## Install PHP dependencies without dev packages in the composer runtime container @printf "$(COMPOSE) $(GREEN)Installing PHP dependencies (no-dev) in $(COMPOSER_RUNTIME)$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs" composer-require: ## Require a PHP package in the composer runtime container (usage: make composer-require package=vendor/package) ifndef package $(error package variable is required: make composer-require package=vendor/package) endif @printf "$(COMPOSE) $(MAGNIFY) Requiring package $(package) in $(COMPOSER_RUNTIME)$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer require $(package) --ignore-platform-reqs" composer-require-dev: ## Require a PHP package as dev in the composer runtime container (usage: make composer-require-dev package=vendor/package) ifndef package $(error package variable is required: make composer-require-dev package=vendor/package) endif @printf "$(COMPOSE) $(MAGNIFY) Requiring dev package $(package) in $(COMPOSER_RUNTIME)$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer require --dev $(package) --ignore-platform-reqs" composer-update: ## Update PHP dependencies in the composer runtime container @printf "$(COMPOSE) $(MAGNIFY) Updating PHP dependencies$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer update --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs" enable-debug: ## Enable Xdebug in the development runtime container @$(DOCKER) up $(DEV_RUNTIME) -d --no-recreate @printf "$(GREEN)$(BUG) Enabling Xdebug in $(DEV_RUNTIME)$(RESET)\n" $(DEV) "bin/xdebug.sh" enable-coverage: ## Enable PCOV code coverage in the composer runtime container @printf "$(GREEN)$(MAGNIFY) Enabling PCOV in $(COMPOSER_RUNTIME)$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "bin/pcov.sh" protoc: ## Generate PHP gRPC code from .proto files @printf "$(PROTO) $(GREEN)Setting up protoc-gen-php-grpc plugin$(RESET)\n" @curl -LOs $(PROTOC_URL) @tar -xzf protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz @printf "$(PROTO) $(GREEN)Generating PHP gRPC code from .proto files$(RESET)\n" @protoc --plugin=./protoc-gen-php-grpc-2025.1.5-darwin-arm64/protoc-gen-php-grpc \ --php_out=./generated \ --php-grpc_out=./generated \ protos/example.proto @printf "$(TRASH) $(GREEN)Cleaning up protoc-gen-php-grpc plugin files$(RESET)\n" @rm -rf $(PROTOC_GEN_DIR) protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz license-check: ## Check license headers in source files @printf "$(MAGNIFY) $(GREEN)Checking license headers$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer run-script tests:license || true" # Developer tasks lint: ## Run linting (phpcs/phpstan) in composer runtime @printf "$(MAGNIFY) $(GREEN)Running linters$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer run-script tests:lint || true" $(COMPOSER) "composer run-script tests:phpstan || true" fmt: ## Format code (php-cs-fixer) @printf "$(MAGNIFY) $(GREEN)Formatting code$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate $(COMPOSER) "composer run-script tests:lint:fix" test: ## Run test suite (phpunit) @printf "$(CHECK) $(GREEN)Running unit tests$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d $(COMPOSER) "composer run-script tests:unit || true" test-coverage: ## Run test suite with coverage report @printf "$(CHECK) $(GREEN)Running unit tests with coverage report$(RESET)\n" @$(DOCKER) up $(COMPOSER_RUNTIME) -d @$(MAKE) enable-coverage $(COMPOSER) "composer run-script tests:unit:coverage || true" # Convenience aliases dev: run ## Alias for start ci: composer-install migrate license-check lint test ## CI-like local flow down: stop ## Alias for stop up: start ## Alias for start .PHONY: help start sh run stop docker-build restart rebuild ps migrate composer-install composer-require composer-require-dev composer-update enable-debug enable-coverage protoc license-check lint fmt test test-coverage dev ci down up