forked from eugeneyan/python-collab-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
310 lines (265 loc) · 10.9 KB
/
Makefile
File metadata and controls
310 lines (265 loc) · 10.9 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
.PHONY: compile-deps setup clean-pyc clean-test clean-venv clean test ty lint format check clean-example docs-install docs-build docs-serve docs-check docs-clean dev-env refresh-containers rebuild-images build-image push-image
# Module name - will be updated by init script
MODULE_NAME := src
# Development Setup
#################
compile-deps: # Compile dependencies from pyproject.toml
uv pip compile pyproject.toml -o requirements.txt
uv pip compile pyproject.toml --extra dev -o requirements-dev.txt
PYTHON_VERSION ?= 3.12
ensure-uv: # Install uv if not present
@which uv > /dev/null || (curl -LsSf https://astral.sh/uv/install.sh | sh)
setup: ensure-uv ensure-scripts # Install dependencies
UV_PYTHON_VERSION=$(PYTHON_VERSION) uv sync --all-extras
$(MAKE) install-hooks
install-hooks: # Install pre-commit hooks if in a git repo with hooks configured
@if [ -d .git ] && [ -f .pre-commit-config.yaml ]; then \
echo "Installing pre-commit hooks..."; \
uv run pre-commit install; \
fi
ensure-scripts: # Ensure scripts directory exists and files are executable
mkdir -p scripts
chmod +x scripts/*.py
# Cleaning
#########
clean-pyc: # Remove Python compilation artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
clean-test: # Remove test and coverage artifacts
rm -f .coverage
rm -f .coverage.*
clean-venv: # Remove virtual environment
rm -rf .venv
clean: clean-pyc clean-test clean-venv
# Testing and Quality Checks
#########################
test: setup # Run pytest with coverage
uv run -m pytest tests --cov=$(MODULE_NAME) --cov-report=term-missing
ty: setup # Run type checking
uv run ty check $(MODULE_NAME)
lint: setup # Run ruff linter with auto-fix
uv run -m ruff check --fix $(MODULE_NAME)
format: setup # Run ruff formatter
uv run -m ruff format $(MODULE_NAME)
check: setup lint format test ty # Run all quality checks
# Local CI Testing with act
###########################
# Detect docker socket (Colima, Docker, or Podman)
define docker_socket
$(shell \
if [ -S $$HOME/.colima/default/docker.sock ]; then \
echo "$$HOME/.colima/default/docker.sock"; \
elif [ -S /var/run/docker.sock ]; then \
echo "/var/run/docker.sock"; \
elif [ -S $$HOME/.docker/run/docker.sock ]; then \
echo "$$HOME/.docker/run/docker.sock"; \
elif [ -S /run/user/$$(id -u)/podman/podman.sock ]; then \
echo "/run/user/$$(id -u)/podman/podman.sock"; \
else \
echo "/var/run/docker.sock"; \
fi \
)
endef
DOCKER_SOCKET := $(docker_socket)
ACT_IMAGE := catthehacker/ubuntu:act-22.04
ACT_ARCH := linux/amd64
act-check: # Check if act is installed, install if missing
@if ! which act > /dev/null 2>&1; then \
echo "⚠️ act is not installed. Installing automatically..."; \
$(MAKE) act-install; \
fi
docker-check: # Check if Docker/Podman/Colima is running
@if ! DOCKER_HOST="unix://$(DOCKER_SOCKET)" docker ps >/dev/null 2>&1; then \
echo "❌ Cannot connect to Docker daemon"; \
echo ""; \
echo "Please start your container runtime first:"; \
echo " • Docker Desktop: Open Docker Desktop app"; \
echo " • Colima: run 'colima start'"; \
echo " • Podman: run 'podman machine start'"; \
echo " • Docker (Linux): run 'sudo systemctl start docker'"; \
echo ""; \
echo "Attempted socket: $(DOCKER_SOCKET)"; \
exit 1; \
fi
@echo "✓ Docker is running (socket: $(DOCKER_SOCKET))"
act-install: ## Install act for local CI testing
@echo "Installing act (GitHub Actions local runner)..."
@if which act > /dev/null 2>&1; then \
echo "✅ act is already installed: $$(which act)"; \
act --version; \
elif which brew > /dev/null 2>&1; then \
echo "📦 Installing act via Homebrew..."; \
brew install act; \
else \
echo "📦 Installing act via install script..."; \
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash; \
fi
@echo ""
@echo "✅ act installed successfully!"
@echo "💡 Run 'make ci-list' to see available workflows"
@echo "💡 Run 'make ci-local' to run CI checks locally"
ci-list: act-check docker-check ## List available GitHub Actions workflows and jobs
@echo "📋 Available workflows and jobs:"
@DOCKER_HOST="unix://$(DOCKER_SOCKET)" act -l
ci-local: act-check docker-check ## Run CI checks locally (tests workflow)
@echo "🔬 Running local CI checks..."
@echo "Using Docker socket: $(DOCKER_SOCKET)"
@echo "Container architecture: $(ACT_ARCH)"
@echo "Image: $(ACT_IMAGE)"
@echo ""
@JOB=$${JOB:-checks}; \
DOCKER_HOST="unix://$(DOCKER_SOCKET)" act pull_request \
-W .github/workflows/tests.yml \
-j $$JOB \
--container-daemon-socket - \
--container-architecture $(ACT_ARCH) \
-P ubuntu-latest=$(ACT_IMAGE)
@echo ""
@echo "✅ Local CI checks complete!"
ci-local-docs: act-check docker-check ## Run documentation build check locally
@echo "📚 Running local documentation build check..."
@DOCKER_HOST="unix://$(DOCKER_SOCKET)" act pull_request \
-W .github/workflows/docs.yml \
-j build-check \
--container-daemon-socket - \
--container-architecture $(ACT_ARCH) \
-P ubuntu-latest=$(ACT_IMAGE)
@echo ""
@echo "✅ Documentation build check complete!"
ci-debug: act-check docker-check ## Fast local test debugging (uses ci-debug.yml workflow)
@echo "🔧 Running CI debug workflow for fast iteration"
@echo "💡 Edit .github/workflows/ci-debug.yml to customize which tests run"
@echo ""
@DOCKER_HOST="unix://$(DOCKER_SOCKET)" act workflow_dispatch \
-W .github/workflows/ci-debug.yml \
--container-daemon-socket - \
--container-architecture $(ACT_ARCH) \
-P ubuntu-latest=$(ACT_IMAGE)
@echo ""
@echo "✅ Debug workflow complete!"
ci-clean: ## Clean up act cache and containers
@echo "🧹 Cleaning up act cache and containers..."
@-docker ps -a | grep "act-" | awk '{print $$1}' | xargs docker rm -f 2>/dev/null || true
@-docker images | grep "act-" | awk '{print $$3}' | xargs docker rmi -f 2>/dev/null || true
@echo "✅ Cleanup complete!"
# Documentation
###############
DOCS_PORT ?= 8000
docs-install: setup ## Install documentation dependencies
@echo "Installing documentation dependencies..."
uv sync --group dev
@echo "Documentation dependencies installed"
docs-build: docs-install ## Build documentation site
@echo "Building documentation..."
uv run mkdocs build --strict
@echo "Documentation built successfully"
@echo "📄 Site location: site/"
@echo "🌐 Open site/index.html in your browser to view"
docs-serve: docs-install ## Serve documentation locally with live reload
@echo "Starting documentation server with live reload..."
@echo "📍 Documentation will be available at:"
@echo " - Local: http://localhost:$(DOCS_PORT)"
@echo "🔄 Changes will auto-reload (press Ctrl+C to stop)"
@echo ""
@echo "💡 To use a different port: make docs-serve DOCS_PORT=9999"
uv run mkdocs serve --dev-addr 0.0.0.0:$(DOCS_PORT)
docs-check: docs-build ## Check documentation build and links
@echo "Checking documentation..."
@echo "📊 Site size: $$(du -sh site/ | cut -f1)"
@echo "📄 Pages built: $$(find site/ -name "*.html" | wc -l)"
@echo "🔗 Checking for common issues..."
@if grep -r "404" site/ >/dev/null 2>&1; then \
echo "⚠️ Found potential 404 errors"; \
else \
echo "✅ No obvious 404 errors found"; \
fi
@if find site/ -name "*.html" -size 0 | grep -q .; then \
echo "⚠️ Found empty HTML files"; \
find site/ -name "*.html" -size 0; \
else \
echo "✅ No empty HTML files found"; \
fi
@echo "Documentation check complete"
docs-clean: ## Clean documentation build files
@echo "Cleaning documentation build files..."
rm -rf site/
rm -rf .cache/
@echo "Documentation cleaned"
# Project Management
##################
clean-example: # Remove example code (use this to start your own project)
rm -rf $(MODULE_NAME)/example.py tests/test_example.py
touch $(MODULE_NAME)/__init__.py tests/__init__.py
init: setup # Initialize a new project
uv run python scripts/init_project.py
# Container Engine Support
########################
# Auto-detect container engine (podman or docker)
CONTAINER_ENGINE ?= $(shell command -v podman >/dev/null 2>&1 && echo podman || echo docker)
# Podman-specific adjustments
ifeq ($(CONTAINER_ENGINE),podman)
# Use podman-compose for compose functionality
COMPOSE_CMD = podman-compose
# Use host UID/GID for rootless containers
CONTAINER_USER_OPTS = --userns=keep-id
# Podman machine status check
PODMAN_MACHINE_RUNNING = $(shell podman machine list --format json 2>/dev/null | grep '"Running": true' >/dev/null && echo yes || echo no)
else
# Docker: use native compose
COMPOSE_CMD = $(CONTAINER_ENGINE) compose
# Docker: use current user's UID/GID to avoid permission issues
CONTAINER_USER_OPTS = --user $(shell id -u):$(shell id -g)
endif
# Docker/Podman Images
#####################
IMAGE_NAME = container-registry.io/python-collab-template
IMAGE_TAG = latest
dev-env: ensure-container-ready refresh-containers
@echo "Spinning up a dev environment using $(CONTAINER_ENGINE)..."
@$(COMPOSE_CMD) -f docker/docker-compose.yml down
@$(COMPOSE_CMD) -f docker/docker-compose.yml up -d dev
@$(CONTAINER_ENGINE) exec -ti composed_dev /bin/bash
refresh-containers: ensure-container-ready
@echo "Rebuilding containers using $(CONTAINER_ENGINE)..."
@$(COMPOSE_CMD) -f docker/docker-compose.yml build
rebuild-images:
@echo "Rebuilding images with the --no-cache flag using $(CONTAINER_ENGINE)..."
@$(COMPOSE_CMD) -f docker/docker-compose.yml build --no-cache
build-image:
@echo Building dev image using $(CONTAINER_ENGINE) and tagging as ${IMAGE_NAME}:${IMAGE_TAG}
@$(COMPOSE_CMD) -f docker/docker-compose.yml down
@$(COMPOSE_CMD) -f docker/docker-compose.yml up -d dev
@$(CONTAINER_ENGINE) tag dev ${IMAGE_NAME}:${IMAGE_TAG}
push-image: build-image
@echo Pushing image to container registry using $(CONTAINER_ENGINE)
@$(CONTAINER_ENGINE) push ${IMAGE_NAME}:${IMAGE_TAG}
# Container Engine Info
######################
ensure-container-ready: # Ensure container engine is ready
ifeq ($(CONTAINER_ENGINE),podman)
@echo "Checking Podman machine status..."
@if [ "$(PODMAN_MACHINE_RUNNING)" = "no" ]; then \
echo "Podman machine is not running. Starting it..."; \
podman machine start; \
echo "Waiting for Podman machine to be ready..."; \
sleep 3; \
fi
@if ! command -v podman-compose >/dev/null 2>&1; then \
echo "Error: podman-compose not found. Install with: brew install podman-compose"; \
exit 1; \
fi
else
@echo "Using Docker engine..."
endif
container-info: # Display detected container engine and configuration
@echo "Container Engine: $(CONTAINER_ENGINE)"
@echo "Compose Command: $(COMPOSE_CMD)"
@echo "User Options: $(CONTAINER_USER_OPTS)"
ifeq ($(CONTAINER_ENGINE),podman)
@echo "Podman Machine Running: $(PODMAN_MACHINE_RUNNING)"
@echo "podman-compose Available: $(shell command -v podman-compose >/dev/null 2>&1 && echo yes || echo no)"
endif
@echo ""
@echo "To override, use: CONTAINER_ENGINE=podman make dev-env"