Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
144 lines (102 loc) · 5.74 KB
/
Copy pathMakefile
File metadata and controls
144 lines (102 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
.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 observability-up observability-down \
prod-init prod-up prod-down prod-ps prod-logs prod-pull prod-backup-now prod-restore prod-rollback grafana-push grafana-push-cloud grafana-pull vps-ssh vps-ps vps-logs vps-status vps-psql vps-datagrip rename
# 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/<owner>/<repo> instead.
APP_NAME := $(shell basename $(CURDIR))
# Production stack (run these on the VPS). Everything reads deploy/.env.prod, created by `make prod-init`.
PROD := docker compose -f deploy/compose.prod.yml --env-file deploy/.env.prod
help: ## Show this help
@grep -E '^[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 bootRun
dev: ## Run with a throwaway Testcontainers DB (no docker-compose needed)
./gradlew 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 after changing dependencies
./gradlew 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
docker compose --env-file $(ENV_FILE) up -d db
db-down: ## Stop the local Postgres
docker compose stop db
up: ## Build the jar + image and run app + db with $(ENV_FILE)
./gradlew bootJar -q
docker compose --env-file $(ENV_FILE) --profile full up --build -d
down: ## Stop the full stack
docker compose --profile full down
image: ## Build the jar and the OCI image (tag: $(APP_NAME))
./gradlew bootJar -q
docker build -t $(APP_NAME) .
observability-up: ## Start local Prometheus + Grafana (http://localhost:3000) + Alloy
docker compose --env-file $(ENV_FILE) --profile observability up -d
observability-down: ## Stop the local observability stack
docker compose --profile observability down
grafana-push: ## Push deploy/grafana/** to the local Grafana (http://localhost:3000)
scripts/grafana-push.sh local
grafana-push-cloud: ## Push deploy/grafana/** to Grafana Cloud (GRAFANA_URL + GRAFANA_API_TOKEN from env or .env)
scripts/grafana-push.sh cloud
grafana-pull: ## Export the dashboard from local Grafana back into deploy/grafana/dashboards
scripts/grafana-push.sh pull
clean: ## Remove build artifacts
./gradlew clean
# ------------------------------------------------------------------------------------------- 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 (SERVICE=app)
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-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 (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-backup-now: ## Run one pg_dump immediately (see deploy/backup)
$(PROD) run --rm backup once
prod-restore: ## Restore a dump: make prod-restore FILE=deploy/backups/<stamp>.dump (stops app replicas first)
@test -n "$(FILE)" || (echo "usage: make prod-restore FILE=deploy/backups/<stamp>.dump" && exit 1)
$(PROD) stop app
$(PROD) exec -T db sh -c 'pg_restore --clean --if-exists --no-owner -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"' < $(FILE)
$(PROD) start 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=<version|sha-xxxxxxx>" && 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"