diff --git a/skills/makefile/SKILL.md b/skills/makefile/SKILL.md index 9089dc9..1b21e02 100644 --- a/skills/makefile/SKILL.md +++ b/skills/makefile/SKILL.md @@ -2,8 +2,8 @@ name: makefile description: "GNU Make automation and build system guidance. Use when creating or maintaining Makefiles, writing Make targets and recipes, or configuring GNU Make build automation. Keywords: Makefile, GNU Make, targets, recipes, build automation." metadata: - version: "2.0.0" - release_date: "2023-02-26" + version: "2.2.0" + release_date: "2026-05-22" --- # Makefile Skill @@ -21,6 +21,7 @@ Guidance for creating and maintaining GNU Make build automation. | Recipe execution, parallel | [recipes.md](references/recipes.md) | | Implicit and pattern rules | [implicit.md](references/implicit.md) | | Common practical patterns | [patterns.md](references/patterns.md) | +| Monorepo / umbrella repos | Monorepo section below + [patterns.md](references/patterns.md) | --- @@ -79,22 +80,133 @@ CFLAGS += -Wall # Append ## Essential Patterns -### Self-Documenting Help +### Colored Help (Required) + +**Always** use explicit, sectioned `@echo` help — never grep/awk auto-generation. + +#### Color hierarchy + +| Variable | Role | Usage | +| -------- | ---- | ----- | +| `BLUE` | Section headers | `$(BLUE)Development servers$(RESET)` | +| `GREEN` | Target names | `$(GREEN)dev-backend$(RESET)` | +| `YELLOW` | Commands, paths, hints | `$(YELLOW)bun run dev$(RESET)`, `$(YELLOW)apps/backend$(RESET)` | + +Define colors once at the top: + +```makefile +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') +``` + +#### Help target rules + +1. `.DEFAULT_GOAL := help` +2. Blank line before first section: `@echo ""` +3. Section header in **BLUE**, blank line between sections +4. Each target line: `@echo " $(GREEN)target$(RESET) description with $(YELLOW)hints$(RESET)"` +5. Reference delegation paths in help: `$(GREEN)make -C apps/backend dev$(RESET)` +6. Use inline color switches mid-line for nested emphasis (see Docker section example) +7. End help with a trailing blank line ```makefile .DEFAULT_GOAL := help -help: ## Show available targets - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ - awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}' +help: + @echo "" + @echo "$(BLUE)Development servers$(RESET)" + @echo " $(GREEN)dev$(RESET) $(YELLOW)turbo dev$(RESET) — all apps" + @echo " $(GREEN)dev-backend$(RESET), $(GREEN)backend$(RESET) API only ($(GREEN)make -C apps/backend dev$(RESET))" + @echo "" + @echo "$(BLUE)Docker ($(RESET)delegates to $(GREEN)apps/backend/Makefile$(RESET)$(BLUE))$(RESET)" + @echo " $(GREEN)docker-up$(RESET) $(GREEN)make -C apps/backend up$(RESET) — Postgres, Redis" + @echo "" +``` -install: ## Install dependencies - uv sync +#### Header boilerplate -test: ## Run tests - uv run pytest +```makefile +.PHONY: \ + help \ + install dev build \ + typecheck check + +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +BACKEND := $(ROOT)/apps/backend + +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') + +SHELL := /bin/bash +.SHELLFLAGS := -eu -o pipefail -c + +.DEFAULT_GOAL := help ``` +### Monorepo / Umbrella Repos (Required for multi-app projects) + +For monorepos and umbrella repos, **generate a Makefile per app** (and per shared package that owns infra, e.g. `packages/db`) then delegate from the root. + +#### Layout + +``` +Makefile # umbrella: help, setup, aggregates, docker +apps/backend/Makefile # dev, build, start, typecheck, test +apps/extension/Makefile # dev, build, zip, typecheck +packages/db/Makefile # db-generate, db-migrate-*, db-seed, db-studio +``` + +#### Root delegation pattern + +```makefile +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +BACKEND := $(ROOT)/apps/backend +EXTENSION := $(ROOT)/apps/extension +DB := $(ROOT)/packages/db + +ensure-apps: + @if [ ! -f "$(BACKEND)/package.json" ] || [ ! -f "$(EXTENSION)/package.json" ]; then \ + echo "$(YELLOW)App checkouts missing. Check apps/ layout.$(RESET)"; \ + exit 1; \ + fi + +dev-backend backend: ensure-apps docker-up + @$(MAKE) -C "$(BACKEND)" dev + +build-seq: ensure-apps + @$(MAKE) -C "$(BACKEND)" build + @$(MAKE) -C "$(EXTENSION)" build + +db-migrate-deploy: ensure-apps + @$(MAKE) -C "$(DB)" db-migrate-deploy +``` + +#### Per-app Makefile rules + +1. Set `ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))` to the app directory +2. Include the same color variables and a scoped `help` target (app name in header) +3. Recipes run commands from `$(ROOT)` — use `@cd "$(ROOT)" && bun run dev` +4. Target aliases: `dev-backend backend:` on one line for shorthand +5. Root help documents every delegation with `make -C path target` + +#### What stays at root vs app + +| Root (umbrella) | Per-app Makefile | +| --------------- | ---------------- | +| `help`, `setup`, `install` | `dev`, `build`, `start` | +| Shared `docker-compose` up/down | App-specific runtime | +| Sequential `build-seq` | Single-app build | +| Turbo aggregates (`typecheck`, `test`) | Single-app typecheck/test | +| Guard targets (`ensure-apps`) | — | + +#### Submodule variant + +When apps are git submodules, add `ensure-submodules` + `submodules-init` and check for `package.json` before delegating (same guard pattern, different message). + ### Platform Detection ```makefile @@ -285,31 +397,48 @@ include config.mk ## Quick Reference ```makefile -# Makefile Template -.DEFAULT_GOAL := help -SHELL := /bin/bash -.SHELLFLAGS := -ec +# Umbrella Makefile (monorepo root) +.PHONY: help ensure-apps install dev-backend build-seq typecheck + +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +BACKEND := $(ROOT)/apps/backend +ADMIN := $(ROOT)/apps/admin -.PHONY: help install test lint format clean +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') -help: ## Show this help - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ - awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}' +SHELL := /bin/bash +.SHELLFLAGS := -eu -o pipefail -c +.DEFAULT_GOAL := help -install: ## Install dependencies - uv sync --extra dev +help: + @echo "" + @echo "$(BLUE)Development servers$(RESET)" + @echo " $(GREEN)dev-backend$(RESET), $(GREEN)backend$(RESET) API ($(GREEN)make -C apps/backend dev$(RESET))" + @echo "" + @echo "$(BLUE)Quality (delegates per app)$(RESET)" + @echo " $(GREEN)typecheck$(RESET) tsc in each app" + @echo "" -test: ## Run tests - uv run pytest tests/ -v +ensure-apps: + @test -f "$(BACKEND)/package.json" || (echo "$(YELLOW)Missing apps/backend$(RESET)" && exit 1) -lint: ## Run linters - uv run ruff check . +install: ensure-apps + bun install + @$(MAKE) -C "$(BACKEND)" install -format: ## Format code - uv run ruff format . +dev-backend backend: ensure-apps + @$(MAKE) -C "$(BACKEND)" dev + +build-seq: ensure-apps + @$(MAKE) -C "$(BACKEND)" build + @$(MAKE) -C "$(ADMIN)" build -clean: ## Clean artifacts - rm -rf build/ dist/ .pytest_cache +typecheck: ensure-apps + @$(MAKE) -C "$(BACKEND)" typecheck + @$(MAKE) -C "$(ADMIN)" typecheck ``` --- diff --git a/skills/makefile/references/patterns.md b/skills/makefile/references/patterns.md index 419e8c6..b10eb9a 100644 --- a/skills/makefile/references/patterns.md +++ b/skills/makefile/references/patterns.md @@ -13,10 +13,22 @@ SHELL := /bin/bash # Phony declarations (group at top) .PHONY: all help install test lint format clean -# Help target (self-documenting) -help: ## Show available targets - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ - awk 'BEGIN {FS = ":.*?## "}; {printf " %-15s %s\n", $$1, $$2}' +# Help target (colored sections — required; use @echo, not grep/awk) +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') + +.DEFAULT_GOAL := help + +help: + @echo "" + @echo "$(BLUE)Setup$(RESET)" + @echo " $(GREEN)install$(RESET) $(YELLOW)bun install$(RESET) at monorepo root" + @echo "" + @echo "$(BLUE)Quality (delegates per app)$(RESET)" + @echo " $(GREEN)typecheck$(RESET) $(YELLOW)tsc$(RESET) in each app" + @echo "" ``` ## Platform Detection @@ -101,6 +113,63 @@ clean: ## Remove artifacts rm -rf .pytest_cache .mypy_cache .ruff_cache htmlcov .coverage ``` +## Monorepo / Umbrella Pattern + +Generate a Makefile per app; root delegates with `$(MAKE) -C`: + +```makefile +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +BACKEND := $(ROOT)/apps/backend +EXTENSION := $(ROOT)/apps/extension +DB := $(ROOT)/packages/db + +ensure-apps: + @test -f "$(BACKEND)/package.json" || (echo "$(YELLOW)Missing apps/backend$(RESET)" && exit 1) + +install: ensure-apps + bun install + @$(MAKE) -C "$(BACKEND)" install + @$(MAKE) -C "$(EXTENSION)" install + +dev-backend backend: ensure-apps docker-up + @$(MAKE) -C "$(BACKEND)" dev + +build-seq: ensure-apps + @$(MAKE) -C "$(BACKEND)" build + @$(MAKE) -C "$(EXTENSION)" build + +db-migrate-deploy: ensure-apps + @$(MAKE) -C "$(DB)" db-migrate-deploy + +typecheck: ensure-apps + @$(MAKE) -C "$(BACKEND)" typecheck + @$(MAKE) -C "$(EXTENSION)" typecheck +``` + +Per-app Makefile (`apps/backend/Makefile`): + +```makefile +ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) + +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') + +.DEFAULT_GOAL := help + +help: + @echo "" + @echo "$(BLUE)Backend ($(RESET)apps/backend$(BLUE))$(RESET)" + @echo " $(GREEN)dev$(RESET) $(YELLOW)bun run dev$(RESET)" + @echo "" + +dev: + @cd "$(ROOT)" && bun run dev +``` + +Root `help` must document every `make -C` delegation path. + ## Node.js Project ```makefile @@ -244,21 +313,25 @@ test: ## Run tests ## Colored Output +Use `printf`-based ANSI variables. Hierarchy: **BLUE** sections, **GREEN** targets, **YELLOW** hints/commands. + ```makefile -# Colors (may not work on all terminals) -RED := \033[31m -GREEN := \033[32m -CYAN := \033[36m -RESET := \033[0m +BLUE := $(shell printf '\033[34m') +GREEN := $(shell printf '\033[32m') +YELLOW := $(shell printf '\033[33m') +RESET := $(shell printf '\033[0m') info: - @echo "$(CYAN)Building...$(RESET)" + @echo "$(BLUE)Building...$(RESET)" success: @echo "$(GREEN)Done!$(RESET)" -error: - @echo "$(RED)Failed!$(RESET)" +warn: + @echo "$(YELLOW)Run: make install$(RESET)" +``` + +Help targets use explicit `@echo` lines — see **Project Setup Pattern** above. ``` ## Guard Patterns