Makefile for DevOps task automation

Ryan Nakamura Feb 2026
1 tab
# Project Makefile
.DEFAULT_GOAL := help

# Variables
APP_NAME := web-app
VERSION := $(shell git describe --tags --always --dirty)
COMMIT := $(shell git rev-parse --short HEAD)
BUILD_TIME := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
REGISTRY := registry.example.com
IMAGE := $(REGISTRY)/$(APP_NAME)

# Environment (override with: make deploy ENV=production)
ENV ?= staging
NAMESPACE ?= $(ENV)
DOCKER_COMPOSE := docker compose

.PHONY: help
help: ## Show this help message
	@echo "Usage: make [target]"
	@echo ""
	@echo "Targets:"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | 		awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'

# === Development ===

.PHONY: dev
dev: ## Start development environment
	$(DOCKER_COMPOSE) up -d
	@echo "Development environment running at http://localhost:3000"

.PHONY: dev-down
dev-down: ## Stop development environment
	$(DOCKER_COMPOSE) down

.PHONY: dev-logs
dev-logs: ## Follow development logs
	$(DOCKER_COMPOSE) logs -f app

.PHONY: install
install: ## Install dependencies
	npm ci

.PHONY: dev-db
dev-db: ## Open database shell
	$(DOCKER_COMPOSE) exec db psql -U postgres myapp

# === Testing ===

.PHONY: test
test: ## Run tests
	npm test

.PHONY: test-watch
test-watch: ## Run tests in watch mode
	npm test -- --watch

.PHONY: test-coverage
test-coverage: ## Run tests with coverage
	npm test -- --coverage
	@echo "Coverage report: coverage/lcov-report/index.html"

.PHONY: lint
lint: ## Run linter
	npm run lint

.PHONY: format
format: ## Format code
	npm run format

.PHONY: check
check: lint test ## Run all checks (lint + test)

# === Building ===

.PHONY: build
build: ## Build Docker image
	docker build 		--build-arg VERSION=$(VERSION) 		--build-arg COMMIT=$(COMMIT) 		--build-arg BUILD_TIME=$(BUILD_TIME) 		-t $(IMAGE):$(VERSION) 		-t $(IMAGE):latest 		.

.PHONY: push
push: build ## Build and push Docker image
	docker push $(IMAGE):$(VERSION)
	docker push $(IMAGE):latest

# === Deployment ===

.PHONY: deploy
deploy: check push ## Full deploy pipeline (check, build, push, deploy)
	@echo "Deploying $(VERSION) to $(ENV)..."
	kubectl set image deployment/$(APP_NAME) 		$(APP_NAME)=$(IMAGE):$(VERSION) 		-n $(NAMESPACE)
	kubectl rollout status deployment/$(APP_NAME) -n $(NAMESPACE)
	@echo "Deploy complete!"

.PHONY: rollback
rollback: ## Rollback to previous version
	kubectl rollout undo deployment/$(APP_NAME) -n $(NAMESPACE)
	kubectl rollout status deployment/$(APP_NAME) -n $(NAMESPACE)

# === Infrastructure ===

.PHONY: tf-init
tf-init: ## Initialize Terraform
	cd terraform && terraform init

.PHONY: tf-plan
tf-plan: ## Plan Terraform changes
	cd terraform && terraform plan -var-file=$(ENV).tfvars -out=tfplan

.PHONY: tf-apply
tf-apply: ## Apply Terraform changes
	cd terraform && terraform apply tfplan

# === Utilities ===

.PHONY: clean
clean: ## Clean build artifacts
	rm -rf dist/ coverage/ node_modules/.cache
	docker image prune -f

.PHONY: info
info: ## Show project info
	@echo "App:     $(APP_NAME)"
	@echo "Version: $(VERSION)"
	@echo "Commit:  $(COMMIT)"
	@echo "Image:   $(IMAGE):$(VERSION)"
	@echo "Env:     $(ENV)"
1 file · makefile Explain with highlit

Makefiles provide a simple, universal task runner for DevOps workflows. Targets define named tasks with optional dependencies. The .PHONY declaration prevents conflicts with files of the same name. Variables set at the top configure reusable values. $(shell ...) executes commands inline. Conditional logic with ifdef and ifeq adapts to environments. Self-documenting targets with ## comment syntax generate help text automatically. Include files split complex Makefiles into manageable pieces. Make is available on virtually every Unix system, requiring no installation. Targets chain together for complex workflows—deploy depends on test, which depends on build. Default target (first target or .DEFAULT_GOAL) runs with bare make.