See More

.DEFAULT_GOAL := help .PHONY: help setup run dev test itest test-scripts build format check lock release-name db-up db-down up down image clean \ config prod-config print-prod prod-init prod-up prod-down prod-ps prod-logs prod-pull prod-rollback vps-ssh vps-ps vps-logs vps-status vps-psql vps-datagrip rename bricks add remove # Prefer .env if present, otherwise fall back to the committed example. ENV_FILE := $(if $(wildcard .env),.env,.env.example) # Local image tag; CI publishes ghcr.io// instead. APP_NAME := $(shell basename $(CURDIR)) # Enabled bricks (bricks/README.md): names from .bricks, comments and blanks dropped. Each enabled brick's Makefile # is included at the bottom of this file, so its targets show up in `make help`. BRICKS ?= $(shell sed -e 's/\#.*//' -e '/^[[:space:]]*$$/d' .bricks 2>/dev/null) # Brick partials of core services (bricks/README.md): merged with -f, never through include (Compose < 5 rejects that). BRICK_OVERRIDES := $(foreach b,$(BRICKS),$(wildcard bricks/$(b)/override.yml)) BRICK_PROD_OVERRIDES := $(foreach b,$(BRICKS),$(wildcard bricks/$(b)/override.prod.yml)) PROD_ENV_FILE ?= deploy/.env.prod # Local stack: every docker compose call below goes through COMPOSE (and brick Makefiles, too). COMPOSE := docker compose -f compose.yml $(addprefix -f ,$(BRICK_OVERRIDES)) --env-file $(ENV_FILE) # Production stack (run these on the VPS). Reads deploy/.env.prod, created by `make prod-init`. # The one place that builds this list: scripts/vps.sh runs `make print-prod` on the VPS instead of repeating it. PROD := docker compose -f deploy/compose.prod.yml $(addprefix -f ,$(BRICK_PROD_OVERRIDES)) --env-file $(PROD_ENV_FILE) # Gradle project under services/ that run/dev/lock/up/image address (SERVICE is the logs filter below). GRADLE_SERVICE ?= app help: ## Show this help @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}' setup: ## One-time: install the commit-msg hook that enforces conventional commits @git config core.hooksPath .githooks && echo "git hooks: .githooks (commit-msg enforces conventional commits)" run: setup ## Run the app (auto-starts the compose DB) ./gradlew :$(GRADLE_SERVICE):bootRun dev: ## Run with a throwaway Testcontainers DB (no docker-compose needed) ./gradlew :$(GRADLE_SERVICE):bootTestRun test: setup ## Run unit tests (no Docker needed) ./gradlew test itest: ## Run integration tests (Testcontainers; one Postgres per fork) ./gradlew integrationTest lock: ## Refresh gradle.lockfile of services/ and of every enabled brick with Java ./gradlew :$(GRADLE_SERVICE):dependencies --write-locks -q $(foreach b,$(BRICKS),$(if $(wildcard bricks/$(b)/java/build.gradle.kts),./gradlew :bricks:$(b):dependencies --write-locks -q;)) release-name: ## Print the version the next push to main would release @scripts/next-version.sh test-scripts: ## Run the bash script tests under scripts/tests scripts/tests/run.sh build: setup ## Full build incl. tests and formatting check ./gradlew build format: ## Auto-format the codebase ./gradlew spotlessApply check: ## Verify formatting without changing files ./gradlew spotlessCheck db-up: ## Start the local Postgres in the background $(COMPOSE) up -d db db-down: ## Stop the local Postgres $(COMPOSE) stop db up: ## Build the jar + image and run app + db with $(ENV_FILE) ./gradlew :$(GRADLE_SERVICE):bootJar -q $(COMPOSE) --profile full up --build -d down: ## Stop the full stack $(COMPOSE) --profile full down config: ## Validate the local compose stack with every enabled brick's override (profiles: full + brick names) $(COMPOSE) $(addprefix --profile ,full $(BRICKS)) config -q image: ## Build the jar and the OCI image (tag: $(APP_NAME)) ./gradlew :$(GRADLE_SERVICE):bootJar -q docker build -f services/$(GRADLE_SERVICE)/Dockerfile -t $(APP_NAME) . clean: ## Remove build artifacts ./gradlew clean # ------------------------------------------------------------------------------------------------------------ bricks bricks: ## List bricks and whether each is enabled (.bricks) @scripts/brick.sh list add: ## Enable a brick: make add BRICK=minio @test -n "$(BRICK)" || (echo "usage: make add BRICK= (make bricks lists them)" && exit 1) scripts/brick.sh add $(BRICK) remove: ## Disable a brick and delete what it added: make remove BRICK=minio @test -n "$(BRICK)" || (echo "usage: make remove BRICK=" && exit 1) scripts/brick.sh remove $(BRICK) # ------------------------------------------------------------------------------------------- production, from this machine vps-ssh: ## Shell on the VPS in the app directory (VPS_SSH from .env) scripts/vps.sh ssh vps-ps: ## Production containers and health scripts/vps.sh ps vps-logs: ## Tail production logs (all services; SERVICE=app to narrow) scripts/vps.sh logs $(SERVICE) vps-status: ## Image tag per replica and what /version answers scripts/vps.sh deploy-status vps-psql: ## psql into the production database through an SSH tunnel (SQL="select 1" for one statement) scripts/vps.sh psql $(if $(SQL),"$(SQL)") vps-datagrip: ## Open the DB tunnel and print a JDBC URL to paste into DataGrip scripts/vps.sh datagrip rename: ## Make the template yours: make rename PKG=com.acme.shop APP=shop @test -n "$(PKG)" -a -n "$(APP)" || (echo "usage: make rename PKG=com.acme.shop APP=shop" && exit 1) scripts/rename-package.sh $(PKG) $(APP) # ---------------------------------------------------------------------------------------------------- production (VPS) prod-init: ## Create deploy/.env.prod with a generated DB password (asks for confirmation) scripts/init-prod-env.sh prod-config: ## Validate the production stack (PROD_ENV_FILE=… to use another env file) $(PROD) config -q print-prod: # Print the production docker compose command (scripts/vps.sh evals it on the VPS) @echo '$(PROD)' prod-up: ## Validate deploy/.env.prod, then start/refresh the production stack and wait for health $(PROD) config -q $(PROD) up -d --remove-orphans --wait prod-down: ## Stop the production stack (volumes are kept) $(PROD) down prod-ps: ## Show production containers and their health $(PROD) ps prod-logs: ## Tail production logs (all services; SERVICE=app to narrow) $(PROD) logs -f --tail=200 $(SERVICE) prod-pull: ## Pull the current APP_IMAGE_TAG now instead of waiting for Watchtower $(PROD) pull app $(PROD) up -d app prod-rollback: ## Pin the app to an earlier image: make prod-rollback TAG=1.4.1 (pauses Watchtower) @test -n "$(TAG)" || (echo "usage: make prod-rollback TAG=" && exit 1) $(PROD) stop watchtower sed -i 's/^APP_IMAGE_TAG=.*/APP_IMAGE_TAG=$(TAG)/' deploy/.env.prod $(PROD) up -d --force-recreate app @echo "Pinned to $(TAG). Watchtower is stopped; when ready to follow releases again:" @echo " sed -i 's/^APP_IMAGE_TAG=.*/APP_IMAGE_TAG=latest/' deploy/.env.prod && $(PROD) up -d app watchtower" # Brick make targets (one Makefile per enabled brick; they may use PROD, ENV_FILE and SERVICE). -include $(foreach b,$(BRICKS),bricks/$(b)/Makefile)