-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
285 lines (260 loc) · 13.8 KB
/
Copy pathMakefile
File metadata and controls
285 lines (260 loc) · 13.8 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
# ─────────────────────────────────────────────────────────────────────────────
# SplitTrip — Developer Bootstrap & Quality Gates
#
# Run once after cloning or switching machines:
# make setup
#
# Run before pushing:
# make check
# ─────────────────────────────────────────────────────────────────────────────
# Default Gradle flags for quality gates (cold run: no build cache, rerun all tasks, no daemon)
GRADLE_FLAGS := --no-build-cache --rerun-tasks --no-daemon --console=plain
GRADLEW := ./gradlew $(GRADLE_FLAGS)
FAST_GRADLE_FLAGS := --console=plain
FAST_GRADLEW := ./gradlew $(FAST_GRADLE_FLAGS)
LOCAL_PROPS := local.properties
HOOK_SRC := scripts/pre-commit
HOOK_DST := .git/hooks/pre-commit
# ─── Colours ─────────────────────────────────────────────────────────────────
RED := \033[0;31m
GREEN := \033[0;32m
YELLOW := \033[1;33m
CYAN := \033[0;36m
NC := \033[0m
.PHONY: help setup hooks local-props doctor fast-check check ktlint detekt test konsist coverage build clean andaluz andaluz-lenient catalog-update firebase prune-branches ai-setup
# ─── Default: show help ───────────────────────────────────────────────────────
help: ## Show this help message
@echo ""
@printf "$(CYAN)SplitTrip — Developer Bootstrap$(NC)\n"
@echo ""
@printf "$(YELLOW)Bootstrap (run once after cloning / switching machines):$(NC)\n"
@printf " $(CYAN)make setup$(NC) Full first-time setup\n"
@echo ""
@printf "$(YELLOW)Available targets:$(NC)\n"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " $(CYAN)%-16s$(NC) %s\n", $$1, $$2}'
@echo ""
# ─── Bootstrap ────────────────────────────────────────────────────────────────
setup: hooks local-props doctor ## Full first-time setup: install hooks, scaffold local.properties, run doctor
@echo ""
@printf "$(GREEN)✅ Setup complete.$(NC)\n"
@echo ""
@printf "$(YELLOW)Next steps (if not done already):$(NC)\n"
@printf " 1. Copy google-services.json into app/\n"
@printf " 2. Add OER_APP_ID_DEBUG and OER_APP_ID_RELEASE to ~/.gradle/gradle.properties\n"
@printf " 3. Open the project in Android Studio and sync Gradle\n"
@echo ""
hooks: ## Install the pre-commit git hook (no Gradle needed)
@if [ ! -d ".git" ]; then \
printf "$(RED)✗ .git directory not found — are you inside the repo root?$(NC)\n"; \
exit 1; \
fi
@mkdir -p .git/hooks
@cp $(HOOK_SRC) $(HOOK_DST)
@chmod +x $(HOOK_DST)
@printf "$(GREEN)✅ Pre-commit hook installed → $(HOOK_DST)$(NC)\n"
local-props: ## Create local.properties (sdk.dir only) if it does not exist
@if [ ! -f "$(LOCAL_PROPS)" ]; then \
printf "$(YELLOW)⏳ Creating local.properties...$(NC)\n"; \
echo "# Auto-generated by 'make setup'" > $(LOCAL_PROPS); \
echo "# This file is for sdk.dir ONLY — API keys do NOT go here." >> $(LOCAL_PROPS); \
echo "# See: ~/.gradle/gradle.properties for OER_APP_ID_DEBUG / OER_APP_ID_RELEASE" >> $(LOCAL_PROPS); \
if [ -n "$$ANDROID_HOME" ]; then \
echo "sdk.dir=$$ANDROID_HOME" >> $(LOCAL_PROPS); \
printf "$(GREEN)✅ local.properties created$(NC) (sdk.dir set from \$$ANDROID_HOME)\n"; \
else \
echo "sdk.dir=/path/to/your/android/sdk" >> $(LOCAL_PROPS); \
printf "$(GREEN)✅ local.properties created$(NC) — update sdk.dir (or set \$$ANDROID_HOME and re-run)\n"; \
fi; \
else \
printf "$(GREEN)✅ local.properties already exists — skipping$(NC)\n"; \
fi
doctor: ## Check that required files and tools are present
@echo ""
@printf "$(YELLOW)🩺 Running doctor checks...$(NC)\n"
@echo ""
@# JDK 21
@if java -version 2>&1 | grep -q 'version "21'; then \
printf " $(GREEN)✅ JDK 21 detected$(NC)\n"; \
else \
printf " $(RED)✗ JDK 21 not found$(NC) — install via SDKMAN or your package manager\n"; \
fi
@# google-services.json
@if [ -f "app/google-services.json" ]; then \
printf " $(GREEN)✅ app/google-services.json present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ app/google-services.json missing$(NC) — download from Firebase Console\n"; \
fi
@# local.properties — sdk.dir
@if grep -q "^sdk.dir=" $(LOCAL_PROPS) 2>/dev/null; then \
SDK_PATH=$$(grep "^sdk.dir=" $(LOCAL_PROPS) | cut -d= -f2); \
if [ -d "$$SDK_PATH" ]; then \
printf " $(GREEN)✅ Android SDK found at $$SDK_PATH$(NC)\n"; \
else \
printf " $(RED)✗ sdk.dir path does not exist: $$SDK_PATH$(NC)\n"; \
fi; \
else \
printf " $(RED)✗ sdk.dir not set in local.properties$(NC)\n"; \
fi
@# OER API key — must be in ~/.gradle/gradle.properties (not local.properties)
@if grep -q "^OER_APP_ID_DEBUG=" ~/.gradle/gradle.properties 2>/dev/null && \
! grep -q "your_" ~/.gradle/gradle.properties 2>/dev/null; then \
printf " $(GREEN)✅ OER_APP_ID_DEBUG is set in ~/.gradle/gradle.properties$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ OER_APP_ID_DEBUG not set$(NC) — add to ~/.gradle/gradle.properties:\n"; \
printf " OER_APP_ID_DEBUG=your_key_here\n"; \
printf " OER_APP_ID_RELEASE=your_key_here\n"; \
printf " $(YELLOW)(not local.properties — those are Gradle properties, not Android properties)$(NC)\n"; \
fi
@# pre-commit hook
@if [ -x "$(HOOK_DST)" ]; then \
printf " $(GREEN)✅ Pre-commit hook installed$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ Pre-commit hook not installed$(NC) — run 'make hooks'\n"; \
fi
@# ─── AI Taxonomy ──────────────────────────────────────────────
@if [ -d ".agents/rules" ] && [ $$(ls -1 .agents/rules/*.md 2>/dev/null | wc -l) -ge 15 ]; then \
printf " $(GREEN)✅ .agents/rules/ present with enough files$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ .agents/rules/ missing or incomplete$(NC)\n"; \
fi
@if [ -d ".agents/skills" ]; then \
printf " $(GREEN)✅ .agents/skills/ present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ .agents/skills/ missing$(NC)\n"; \
fi
@if grep -q "rules" .opencode/opencode.json 2>/dev/null && grep -q "skills" .opencode/opencode.json 2>/dev/null; then \
printf " $(GREEN)✅ .opencode/opencode.json has rules and skills$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ .opencode/opencode.json missing rules or skills$(NC)\n"; \
fi
@# ─── AI Code Intelligence Tools ─────────────────────
@# codebase-memory-mcp binary
@CBM_BIN=$${HOME}/.local/bin/codebase-memory-mcp; \
if [ -x "$$CBM_BIN" ]; then \
printf " $(GREEN)✅ codebase-memory-mcp present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ codebase-memory-mcp not found$(NC) — run 'make ai-setup'\n"; \
fi
@# uv
@if command -v uv >/dev/null 2>&1 || [ -x "$${HOME}/.local/bin/uv" ]; then \
printf " $(GREEN)✅ uv present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ uv not found$(NC) — run 'make ai-setup'\n"; \
fi
@# Headroom binary
@if command -v headroom >/dev/null 2>&1 || [ -x "$${HOME}/.local/bin/headroom" ]; then \
printf " $(GREEN)✅ Headroom present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ Headroom not found$(NC) — run 'make ai-setup'\n"; \
fi
@# graphify
@if command -v graphify >/dev/null 2>&1; then \
printf " $(GREEN)✅ graphify present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ graphify not found$(NC) — run 'make ai-setup'\n"; \
fi
@# rtk (Rust Token Killer)
@if command -v rtk >/dev/null 2>&1 || [ -x "$${HOME}/.cargo/bin/rtk" ]; then \
printf " $(GREEN)✅ rtk present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ rtk not found$(NC) — run 'make ai-setup' or 'cargo install rtk'\n"; \
fi
@# codebase-memory-mcp index
@if [ -d "$${HOME}/.cache/codebase-memory-mcp" ]; then \
printf " $(GREEN)✅ codebase-memory-mcp index present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ codebase-memory-mcp index missing$(NC) — run 'make ai-setup'\n"; \
fi
@# Graphify index
@if [ -f "graphify-out/graph.json" ]; then \
printf " $(GREEN)✅ Graphify index present$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ Graphify index missing$(NC) — run 'make ai-setup'\n"; \
fi
@# opencode.jsonc has codebase-memory-mcp entry
@OPENCODE_CFG="$${HOME}/.config/opencode/opencode.jsonc"; \
if [ -f "$$OPENCODE_CFG" ] && grep -q "codebase-memory-mcp" "$$OPENCODE_CFG" 2>/dev/null; then \
printf " $(GREEN)✅ opencode.jsonc has codebase-memory-mcp entry$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ opencode.jsonc missing codebase-memory-mcp entry$(NC) — run 'make ai-setup'\n"; \
fi
@# Gemini MCP config has entries
@GEMINI_CFG="$${HOME}/.gemini/config/mcp_config.json"; \
if [ -f "$$GEMINI_CFG" ] && grep -q "codebase-memory-mcp" "$$GEMINI_CFG" 2>/dev/null; then \
printf " $(GREEN)✅ Gemini MCP has codebase-memory-mcp entry$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ Gemini MCP missing codebase-memory-mcp entry$(NC) — run 'make ai-setup'\n"; \
fi; \
if [ -f "$$GEMINI_CFG" ] && grep -q '"graphify"' "$$GEMINI_CFG" 2>/dev/null; then \
printf " $(GREEN)✅ Gemini MCP has graphify entry$(NC)\n"; \
else \
printf " $(YELLOW)⚠️ Gemini MCP missing graphify entry$(NC) — run 'make ai-setup'\n"; \
fi
@echo ""
# ─── Quality gates (mirrors CI) ───────────────────────────────────────────────
fast-check: andaluz-lenient ## Fast incremental check using Gradle daemon & build cache (for rapid iteration)
@printf "$(YELLOW)⏳ Running fast incremental quality checks...$(NC)\n"
@$(FAST_GRADLEW) ktlintCheck detekt lintDebug :konsist-tests:test --continue
@$(FAST_GRADLEW) jacocoMergedReport --continue
@printf "$(YELLOW)⏳ Checking LINE coverage gates (overall + per-file, ≥ 80%%)...$(NC)\n"
@python3 scripts/check_coverage.py
check: clean andaluz-lenient ## Run all local quality gates from a 100% cold state before pushing (single-pass Gradle execution, mirrors CI)
@printf "$(YELLOW)⏳ Running full cold quality gates (single-pass Gradle execution)...$(NC)\n"
@$(GRADLEW) ktlintFormat ktlintCheck detekt lintDebug :konsist-tests:test --continue
@$(GRADLEW) jacocoMergedReport --continue
@printf "$(YELLOW)⏳ Checking LINE coverage gates (overall + per-file, ≥ 80%%)...$(NC)\n"
@python3 scripts/check_coverage.py
andaluz: ## Automatically generate Andaluz string resources from Spanish strings.xml (fails if python andaluh package is missing)
@if python3 -c "import andaluh" >/dev/null 2>&1; then \
printf "$(YELLOW)⏳ Generating Andaluz strings...$(NC)\n"; \
$(GRADLEW) generateAndaluzStrings; \
else \
printf "$(RED)✗ Python package 'andaluh' not found. Please run: pip install andaluh --break-system-packages$(NC)\n"; \
exit 1; \
fi
andaluz-lenient:
@if python3 -c "import andaluh" >/dev/null 2>&1; then \
printf "$(YELLOW)⏳ Generating Andaluz strings...$(NC)\n"; \
$(GRADLEW) generateAndaluzStrings; \
else \
printf "$(YELLOW)⚠️ Skipping Andaluz translation (python 'andaluh' package not found)$(NC)\n"; \
fi
test: ## Run all unit tests (no coverage report)
@printf "$(YELLOW)⏳ Running unit tests...$(NC)\n"
@$(GRADLEW) test --continue
ktlint: ## Run ktlint format + check (auto-fixes what it can, fails on unfixable issues)
@printf "$(YELLOW)⏳ Running ktlint format...$(NC)\n"
@$(GRADLEW) ktlintFormat --continue || true
@printf "$(YELLOW)⏳ Running ktlint check...$(NC)\n"
@$(GRADLEW) ktlintCheck
detekt: ## Run detekt static analysis (finds code quality/complexity violations)
@printf "$(YELLOW)⏳ Running detekt check...$(NC)\n"
@$(GRADLEW) detekt
konsist: ## Run Konsist architecture tests (file-size limit, naming, dependency rules)
@printf "$(YELLOW)⏳ Running Konsist architecture tests...$(NC)\n"
@$(GRADLEW) :konsist-tests:test
coverage: ## Run all unit tests, generate merged JaCoCo report, and gate on overall + per-file LINE coverage (≥80%%)
@printf "$(YELLOW)⏳ Running tests + generating merged coverage report...$(NC)\n"
@$(GRADLEW) jacocoMergedReport --continue
@printf "$(YELLOW)⏳ Checking LINE coverage gates (overall + per-file, ≥ 80%%)...$(NC)\n"
@python3 scripts/check_coverage.py
build: ## Compile all modules (debug)
@printf "$(YELLOW)⏳ Compiling debug...$(NC)\n"
@$(GRADLEW) compileDebugKotlin --continue
# ─── Utility ──────────────────────────────────────────────────────────────────
firebase: ## Deploy all configured resources to Firebase
@printf "$(YELLOW)⏳ Deploying to Firebase...$(NC)\n"
@npx firebase-tools deploy
clean: ## Clean all Gradle build outputs
@printf "$(YELLOW)⏳ Cleaning build outputs...$(NC)\n"
@$(GRADLEW) clean
catalog-update: ## Check and update Version Catalog dependencies (on-demand)
@printf "$(YELLOW)⏳ Checking and updating Version Catalog...$(NC)\n"
@$(GRADLEW) versionCatalogUpdate
ai-setup: ## Install and configure AI code-intelligence tools (codebase-memory-mcp + Graphify)
@printf "$(YELLOW)⏳ Setting up AI code-intelligence tools...$(NC)\n"
@./scripts/ai-setup.sh
prune-branches: ## Fetch remote changes and delete local branches that are gone on the remote
@printf "$(YELLOW)⏳ Pruning gone branches...$(NC)\n"
@./scripts/prune-branches.sh