-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
126 lines (101 loc) · 5.27 KB
/
Copy pathMakefile
File metadata and controls
126 lines (101 loc) · 5.27 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
# Task runner for the clock_website monorepo.
#
# Layout
# web/ application workspace (npm project)
# nginx/ edge reverse proxy
# webhook/ production deployer
# scripts/ deploy and host-bootstrap helpers
-include .env
DEPLOY_HOST ?=
DEPLOY_USER ?= $(USER)
DEPLOY_DIR ?= /opt/clock_website
.PHONY: .env install dev-up dev-down dev-reset dev-logs dev-health \
dev-tunnel-up dev-tunnel-down dev-tunnel-logs \
test lint format typecheck check \
prod-deploy prod-status prod-logs prod-verify env-check \
deploy-remote bootstrap-remote
# ─── Local setup ───────────────────────────────────────────────
.env:
@cp .env.sample .env
@echo "✓ Created .env from .env.sample"
install:
cd web && npm ci
# ─── Development ───────────────────────────────────────────────
dev-up: .env
docker compose --env-file .env up -d --build
@docker compose ps
dev-down:
# --profile tunnel so an opt-in dev tunnel is stopped too, not orphaned.
docker compose --env-file .env --profile tunnel down
# Rebuild from scratch. Needed when package.json changes, because node_modules
# lives in an anonymous volume that is only seeded on first creation.
dev-reset:
@echo "▶ Stopping dev containers and clearing anonymous volumes..."
docker compose down -v
@echo "▶ Rebuilding images and restarting the stack..."
docker compose --env-file .env up -d --build
@echo "✓ Dev stack reset. Run 'make dev-health' to verify."
dev-logs:
docker compose logs -f
dev-health:
@PORT=$${NGINX_HOST_PORT:-8100}; \
echo "▶ Checking the dev stack on http://127.0.0.1:$$PORT..."; \
curl -sf "http://127.0.0.1:$$PORT/healthz" > /dev/null && echo "✓ Edge: OK" || echo "✗ Edge: FAIL"; \
curl -sf "http://127.0.0.1:$$PORT/" > /dev/null && echo "✓ App: OK" || echo "✗ App: FAIL"
# ─── Containerized Cloudflare Tunnel for the dev stack ────────────
# Opt-in: `make dev-up` does NOT start it. Lives in the clock-dev project,
# fully separate from the production connector.
dev-tunnel-up: .env
@if ! grep -qE '^CLOUDFLARE_TUNNEL_TOKEN=.+' .env; then \
echo "✗ CLOUDFLARE_TUNNEL_TOKEN is not set in .env"; \
echo " Create a tunnel, then add its token to .env (see README > Cloudflare Tunnel)."; \
exit 1; \
fi
docker compose --env-file .env --profile tunnel up -d cloudflared
@docker compose --env-file .env --profile tunnel ps cloudflared
dev-tunnel-down:
docker compose --env-file .env --profile tunnel rm -sf cloudflared
dev-tunnel-logs:
docker compose --env-file .env --profile tunnel logs -f cloudflared
# ─── Quality gates (run on the host, no Docker required) ──────────
test:
cd web && npm test
lint:
cd web && npm run lint
format:
cd web && npm run format
typecheck:
cd web && npm run typecheck
check: lint typecheck test
@echo "✓ Full check passed (lint + types + tests)."
# ─── Production ────────────────────────────────────────────────
prod-deploy:
@test -f .env.prod || { echo "✗ .env.prod is missing. Copy .env.sample and fill it in."; exit 1; }
@echo "▶ Building/pulling and replacing production containers..."
docker compose -p clock-prod -f docker-compose.prod.yml --env-file .env.prod up -d --build --remove-orphans
@docker compose -p clock-prod -f docker-compose.prod.yml ps
prod-status:
docker compose -p clock-prod -f docker-compose.prod.yml ps
prod-logs:
docker compose -p clock-prod -f docker-compose.prod.yml logs -f
# Verify through the loopback-only published port, exactly as the tunnel sees it.
prod-verify:
@PORT=$${PROD_VERIFY_PORT:-9418}; \
echo "▶ Verifying the production stack on http://127.0.0.1:$$PORT..."; \
curl -sf "http://127.0.0.1:$$PORT/healthz" > /dev/null && echo "✓ Edge: OK" || { echo "✗ Edge: FAIL"; exit 1; }; \
curl -sf "http://127.0.0.1:$$PORT/" > /dev/null && echo "✓ App: OK" || { echo "✗ App: FAIL"; exit 1; }
# Catches an unset secret before Docker starts a half-configured stack.
env-check:
@test -f .env.prod || { echo "✗ .env.prod is missing."; exit 1; }
@grep -qE '^WEBHOOK_TOKEN=.+' .env.prod && echo "✓ WEBHOOK_TOKEN is set" || { echo "✗ WEBHOOK_TOKEN is empty"; exit 1; }
@grep -qE '^CLOUDFLARE_TUNNEL_TOKEN=.+' .env.prod && echo "✓ CLOUDFLARE_TUNNEL_TOKEN is set" || { echo "✗ CLOUDFLARE_TUNNEL_TOKEN is empty"; exit 1; }
@echo "✓ Environment check complete."
# ─── Remote host helpers ───────────────────────────────────────
deploy-remote:
@test -n "$(DEPLOY_HOST)" || { echo "Error: DEPLOY_HOST is not set. Run with DEPLOY_HOST=your-host make deploy-remote"; exit 1; }
@echo "▶ Deploying on $(DEPLOY_USER)@$(DEPLOY_HOST):$(DEPLOY_DIR)..."
ssh -t $(DEPLOY_USER)@$(DEPLOY_HOST) "cd $(DEPLOY_DIR) && ./scripts/deploy.sh"
bootstrap-remote:
@test -n "$(DEPLOY_HOST)" || { echo "Error: DEPLOY_HOST is not set. Run with DEPLOY_HOST=your-host make bootstrap-remote"; exit 1; }
@echo "▶ Bootstrapping $(DEPLOY_USER)@$(DEPLOY_HOST)..."
ssh -t $(DEPLOY_USER)@$(DEPLOY_HOST) "sudo ./scripts/bootstrap-host.sh"