Makefile: основы

Makefile — файл с набором именованных команд (targets) для автоматизации типовых задач проекта: make install, make test, make deploy — единый интерфейс для разных инструментов.

Зачем нужно

В проекте накапливаются длинные команды: docker compose up -d --build, npm run test -- --coverage --watch=false, kubectl apply -f k8s/. Makefile превращает их в короткие make up, make test, make deploy. Это живая документация — новый разработчик видит make help и понимает все доступные команды.

Где используется

  • Стандартизация команд в команде (один make test для всех)
  • CI/CD: пайплайн вызывает make ci вместо копирования длинных команд
  • Управление Docker Compose: make up, make down, make logs
  • Автоматизация деплоя: make deploy-staging, make deploy-prod

Основной контент

Синтаксис Makefile

# ВАЖНО: отступы в теле target — строго TAB, не пробелы!

target-name: зависимость1 зависимость2
	команда1
	команда2

Практический Makefile для Node.js проекта

# Makefile
.PHONY: install dev build test lint clean docker-up docker-down deploy

# Переменные
IMAGE_NAME := myapp
TAG := $(shell git rev-parse --short HEAD)
DOCKER_REGISTRY := myuser

# По умолчанию — показать help
.DEFAULT_GOAL := help

help: ## Показать список команд
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
	  awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'

install: ## Установить зависимости
	npm ci

dev: ## Запустить в режиме разработки
	npm run dev

build: ## Собрать TypeScript
	npm run build

test: ## Запустить тесты с coverage
	npm test -- --coverage

lint: ## Проверить линтером
	npm run lint
	npx tsc --noEmit

ci: install lint test build ## Полный CI (lint + test + build)

clean: ## Очистить артефакты сборки
	rm -rf dist/ coverage/ node_modules/

# Docker
docker-build: ## Собрать Docker-образ
	docker build -t $(IMAGE_NAME):$(TAG) .
	docker tag $(IMAGE_NAME):$(TAG) $(IMAGE_NAME):latest

docker-push: docker-build ## Пушнуть образ в registry
	docker tag $(IMAGE_NAME):$(TAG) $(DOCKER_REGISTRY)/$(IMAGE_NAME):$(TAG)
	docker push $(DOCKER_REGISTRY)/$(IMAGE_NAME):$(TAG)

docker-up: ## Запустить docker-compose
	docker compose up -d

docker-down: ## Остановить docker-compose
	docker compose down

logs: ## Показать логи приложения
	docker compose logs -f api

# Деплой
deploy-staging: docker-push ## Задеплоить на staging
	ssh staging-server "docker pull $(DOCKER_REGISTRY)/$(IMAGE_NAME):$(TAG) && \
	  docker stop api || true && \
	  docker run -d --name api -p 3000:3000 $(DOCKER_REGISTRY)/$(IMAGE_NAME):$(TAG)"

db-migrate: ## Выполнить миграции БД
	npm run db:migrate

Использование

# Список команд
make help

# Запуск
make install
make dev
make test
make ci

# Docker
make docker-up
make logs
make deploy-staging

Переменные и override

# Переопределить переменную из командной строки
make docker-build IMAGE_NAME=myother-app TAG=v2.0.0

# Использование переменных окружения
export TAG=v1.5.0
make docker-push

Частые ошибки

  • Пробелы вместо TAB в теле target — Makefile не работает (Makefile:5: *** missing separator)
  • Не указывать .PHONY для non-file targets — Make проверяет наличие файла с таким именем и может не выполнить команду
  • Забыть про зависимости между targets: deploy должен зависеть от build
  • Слишком длинные однострочные команды без переноса (\)

Связанные темы

Ресурсы