Files
tankstopp-app/Makefile
T
2025-07-07 01:44:12 +02:00

443 lines
16 KiB
Makefile

# TankStopp Makefile
# Build and development management for TankStopp fuel tracking application
.PHONY: help build dev prod test clean format generate watch install deps migrate seed docker run
# Default target
.DEFAULT_GOAL := help
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
GOMOD=$(GOCMD) mod
BINARY_NAME=tankstopp
BINARY_PATH=./$(BINARY_NAME)
MAIN_PATH=./cmd/main.go
# Configuration parameters
CONFIG_PATH=config.yaml
CONFIG_DEV_PATH=config.development.yaml
CONFIG_PROD_PATH=config.production.yaml
# Templ parameters
TEMPL_CMD=go tool templ
VIEWS_PATH=./internal/views
# Database parameters
DB_PATH=./fuel_stops.db
MIGRATIONS_PATH=./migrations
# Colors for output
RED=\033[0;31m
GREEN=\033[0;32m
YELLOW=\033[1;33m
BLUE=\033[0;34m
NC=\033[0m
help: ## Show this help message
@echo "TankStopp Build System"
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@echo ""
@echo "Configuration:"
@echo " Set CONFIG_ENV to 'development' or 'production' to use specific configs"
@echo " Example: make run CONFIG_ENV=development"
install: ## Install required tools and dependencies
@echo "$(BLUE)[INFO]$(NC) Installing required tools..."
@$(GOGET) -u github.com/a-h/templ/cmd/templ@latest
@$(GOMOD) tidy
@echo "$(GREEN)[SUCCESS]$(NC) Tools installed successfully"
deps: ## Download and tidy dependencies
@echo "$(BLUE)[INFO]$(NC) Downloading dependencies..."
@$(GOMOD) download
@$(GOMOD) tidy
@echo "$(GREEN)[SUCCESS]$(NC) Dependencies updated"
format: ## Format Go code and templ files
@echo "$(BLUE)[INFO]$(NC) Formatting code..."
@$(GOCMD) fmt ./...
@if command -v $(TEMPL_CMD) > /dev/null 2>&1; then \
$(TEMPL_CMD) fmt $(VIEWS_PATH)/; \
echo "$(GREEN)[SUCCESS]$(NC) Code formatted successfully"; \
else \
echo "$(YELLOW)[WARNING]$(NC) templ not found, skipping templ formatting"; \
fi
generate: ## Generate Go code from templ files
@echo "$(BLUE)[INFO]$(NC) Generating Go code from templ files..."
@if command -v $(TEMPL_CMD) > /dev/null 2>&1; then \
$(TEMPL_CMD) generate $(VIEWS_PATH)/; \
echo "$(GREEN)[SUCCESS]$(NC) Go code generated successfully"; \
else \
echo "$(RED)[ERROR]$(NC) templ not found. Run 'make install' first"; \
exit 1; \
fi
build: generate ## Build the application
@echo "$(BLUE)[INFO]$(NC) Building application..."
@$(GOBUILD) -o $(BINARY_NAME) $(MAIN_PATH)
@echo "$(GREEN)[SUCCESS]$(NC) Application built successfully"
dev: ## Development build (format, generate, build)
@echo "$(BLUE)[INFO]$(NC) Starting development build..."
@$(MAKE) format
@$(MAKE) generate
@$(MAKE) build
@echo "$(GREEN)[SUCCESS]$(NC) Development build completed"
prod: ## Production build (format, generate, test, build with optimizations)
@echo "$(BLUE)[INFO]$(NC) Starting production build..."
@$(MAKE) format
@$(MAKE) generate
@$(MAKE) test
@$(GOBUILD) -ldflags="-s -w" -o $(BINARY_NAME) $(MAIN_PATH)
@echo "$(GREEN)[SUCCESS]$(NC) Production build completed"
test: ## Run tests
@echo "$(BLUE)[INFO]$(NC) Running tests..."
@$(GOTEST) -v ./...
@echo "$(GREEN)[SUCCESS]$(NC) All tests passed"
test-coverage: ## Run tests with coverage
@echo "$(BLUE)[INFO]$(NC) Running tests with coverage..."
@$(GOTEST) -v -coverprofile=coverage.out ./...
@$(GOCMD) tool cover -html=coverage.out -o coverage.html
@echo "$(GREEN)[SUCCESS]$(NC) Coverage report generated: coverage.html"
clean: ## Clean build artifacts and generated files
@echo "$(BLUE)[INFO]$(NC) Cleaning build artifacts..."
@$(GOCLEAN)
@rm -f $(BINARY_NAME)
@rm -f coverage.out coverage.html
@find $(VIEWS_PATH) -name "*_templ.go" -delete
@echo "$(GREEN)[SUCCESS]$(NC) Cleaned build artifacts"
run: build ## Build and run the application
@echo "$(BLUE)[INFO]$(NC) Running application..."
@$(BINARY_PATH)
run-hot: ## Run application in development mode with hot reload
@echo "$(BLUE)[INFO]$(NC) Starting development server..."
@if command -v air > /dev/null 2>&1; then \
air; \
else \
echo "$(YELLOW)[WARNING]$(NC) air not found, running without hot reload"; \
$(MAKE) run; \
fi
watch: ## Watch for changes and rebuild (requires entr)
@echo "$(BLUE)[INFO]$(NC) Starting watch mode..."
@if command -v entr > /dev/null 2>&1; then \
find $(VIEWS_PATH) -name "*.templ" | entr -r make dev; \
else \
echo "$(RED)[ERROR]$(NC) entr not found. Install with: brew install entr (macOS) or apt-get install entr (Linux)"; \
exit 1; \
fi
migrate: ## Run database migrations
@echo "$(BLUE)[INFO]$(NC) Running database migrations..."
@if [ -f $(BINARY_PATH) ]; then \
$(BINARY_PATH) -migrate; \
else \
echo "$(RED)[ERROR]$(NC) Binary not found. Run 'make build' first"; \
exit 1; \
fi
seed: ## Seed database with sample data
@echo "$(BLUE)[INFO]$(NC) Seeding database with sample data..."
@if [ -f $(BINARY_PATH) ]; then \
$(BINARY_PATH) -seed; \
else \
echo "$(RED)[ERROR]$(NC) Binary not found. Run 'make build' first"; \
exit 1; \
fi
db-reset: ## Reset database (drop and recreate)
@echo "$(BLUE)[INFO]$(NC) Resetting database..."
@rm -f $(DB_PATH)
@$(MAKE) migrate
@echo "$(GREEN)[SUCCESS]$(NC) Database reset completed"
docker-build: ## Build Docker image
@echo "$(BLUE)[INFO]$(NC) Building Docker image..."
@docker build -t tankstopp:latest .
@echo "$(GREEN)[SUCCESS]$(NC) Docker image built successfully"
docker-run: ## Run application in Docker container
@echo "$(BLUE)[INFO]$(NC) Running Docker container..."
@docker run -p 8080:8080 -v $(PWD)/data:/app/data tankstopp:latest
docker-dev: ## Run Docker container in development mode
@echo "$(BLUE)[INFO]$(NC) Running Docker container in development mode..."
@docker run -p 8080:8080 -v $(PWD):/app -v $(PWD)/data:/app/data tankstopp:latest
lint: ## Run linters
@echo "$(BLUE)[INFO]$(NC) Running linters..."
@if command -v golangci-lint > /dev/null 2>&1; then \
golangci-lint run; \
echo "$(GREEN)[SUCCESS]$(NC) Linting completed"; \
else \
echo "$(YELLOW)[WARNING]$(NC) golangci-lint not found, skipping linting"; \
fi
vet: ## Run go vet
@echo "$(BLUE)[INFO]$(NC) Running go vet..."
@$(GOCMD) vet ./...
@echo "$(GREEN)[SUCCESS]$(NC) Vet completed"
mod-update: ## Update Go modules
@echo "$(BLUE)[INFO]$(NC) Updating Go modules..."
@$(GOGET) -u ./...
@$(GOMOD) tidy
@echo "$(GREEN)[SUCCESS]$(NC) Modules updated"
security: ## Run security scan
@echo "$(BLUE)[INFO]$(NC) Running security scan..."
@if command -v gosec > /dev/null 2>&1; then \
gosec ./...; \
echo "$(GREEN)[SUCCESS]$(NC) Security scan completed"; \
else \
echo "$(YELLOW)[WARNING]$(NC) gosec not found, skipping security scan"; \
fi
benchmark: ## Run benchmarks
@echo "$(BLUE)[INFO]$(NC) Running benchmarks..."
@$(GOTEST) -bench=. -benchmem ./...
@echo "$(GREEN)[SUCCESS]$(NC) Benchmarks completed"
all: ## Full build pipeline (format, generate, test, build)
@echo "$(BLUE)[INFO]$(NC) Running full build pipeline..."
@$(MAKE) format
@$(MAKE) generate
@$(MAKE) test
@$(MAKE) build
@echo "$(GREEN)[SUCCESS]$(NC) Full build pipeline completed"
check: ## Run all checks (format, vet, lint, test)
@echo "$(BLUE)[INFO]$(NC) Running all checks..."
@$(MAKE) format
@$(MAKE) vet
@$(MAKE) lint
@$(MAKE) test
@echo "$(GREEN)[SUCCESS]$(NC) All checks completed"
install-tools: ## Install development tools
@echo "$(BLUE)[INFO]$(NC) Installing development tools..."
@$(GOGET) -u github.com/a-h/templ/cmd/templ@latest
@$(GOGET) -u github.com/cosmtrek/air@latest
@$(GOGET) -u github.com/golangci/golangci-lint/cmd/golangci-lint@latest
@$(GOGET) -u github.com/securecodewarrior/gosec/v2/cmd/gosec@latest
@echo "$(GREEN)[SUCCESS]$(NC) Development tools installed"
version: ## Show version information
@echo "TankStopp Build System"
@echo "Go version: $$(go version)"
@if command -v $(TEMPL_CMD) > /dev/null 2>&1; then \
echo "Templ version: $$(templ version)"; \
fi
@if [ -f $(BINARY_PATH) ]; then \
echo "Binary: $(BINARY_PATH)"; \
echo "Size: $$(du -h $(BINARY_PATH) | cut -f1)"; \
fi
clean-all: clean ## Clean everything including dependencies
@echo "$(BLUE)[INFO]$(NC) Cleaning all artifacts and dependencies..."
@$(GOMOD) clean -cache
@echo "$(GREEN)[SUCCESS]$(NC) Everything cleaned"
# Docker targets
docker-build: ## Build Docker image
@echo "$(BLUE)[INFO]$(NC) Building Docker image..."
@./scripts/docker/build.sh --tag $(BINARY_NAME):latest --env production
@echo "$(GREEN)[SUCCESS]$(NC) Docker image built successfully"
docker-build-dev: ## Build Docker image for development
@echo "$(BLUE)[INFO]$(NC) Building development Docker image..."
@./scripts/docker/build.sh --tag $(BINARY_NAME):dev --env development
@echo "$(GREEN)[SUCCESS]$(NC) Development Docker image built successfully"
docker-run: ## Run Docker container
@echo "$(BLUE)[INFO]$(NC) Running Docker container..."
@docker run -d --name $(BINARY_NAME) -p 8080:8080 \
-v tankstopp_data:/app/data \
$(BINARY_NAME):latest
@echo "$(GREEN)[SUCCESS]$(NC) Container started on http://localhost:8080"
docker-run-dev: ## Run Docker container in development mode
@echo "$(BLUE)[INFO]$(NC) Running development Docker container..."
@docker run -d --name $(BINARY_NAME)-dev -p 8081:8080 \
-v tankstopp_dev_data:/app/data \
-e TANKSTOPP_APP_DEBUG=true \
$(BINARY_NAME):dev
@echo "$(GREEN)[SUCCESS]$(NC) Development container started on http://localhost:8081"
docker-stop: ## Stop Docker container
@echo "$(BLUE)[INFO]$(NC) Stopping Docker containers..."
@docker stop $(BINARY_NAME) $(BINARY_NAME)-dev 2>/dev/null || true
@docker rm $(BINARY_NAME) $(BINARY_NAME)-dev 2>/dev/null || true
@echo "$(GREEN)[SUCCESS]$(NC) Docker containers stopped"
docker-logs: ## Show Docker container logs
@echo "$(BLUE)[INFO]$(NC) Showing Docker logs..."
@docker logs -f $(BINARY_NAME) 2>/dev/null || docker logs -f $(BINARY_NAME)-dev 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) No running containers found"
docker-clean: ## Clean Docker resources
@echo "$(BLUE)[INFO]$(NC) Cleaning Docker resources..."
@docker container prune -f
@docker image prune -f
@docker volume prune -f
@docker network prune -f
@echo "$(GREEN)[SUCCESS]$(NC) Docker cleanup completed"
docker-compose-up: ## Start services with docker-compose
@echo "$(BLUE)[INFO]$(NC) Starting services with docker-compose..."
@docker-compose up -d
@echo "$(GREEN)[SUCCESS]$(NC) Services started"
docker-compose-down: ## Stop services with docker-compose
@echo "$(BLUE)[INFO]$(NC) Stopping services with docker-compose..."
@docker-compose down
@echo "$(GREEN)[SUCCESS]$(NC) Services stopped"
docker-compose-logs: ## Show docker-compose logs
@echo "$(BLUE)[INFO]$(NC) Showing docker-compose logs..."
@docker-compose logs -f
docker-deploy: ## Deploy using deployment script
@echo "$(BLUE)[INFO]$(NC) Deploying application..."
@./scripts/docker/deploy.sh deploy --env production
@echo "$(GREEN)[SUCCESS]$(NC) Application deployed"
docker-deploy-dev: ## Deploy development environment
@echo "$(BLUE)[INFO]$(NC) Deploying development environment..."
@./scripts/docker/deploy.sh deploy --env development
@echo "$(GREEN)[SUCCESS]$(NC) Development environment deployed"
docker-status: ## Show Docker deployment status
@echo "$(BLUE)[INFO]$(NC) Docker deployment status:"
@./scripts/docker/deploy.sh status
docker-backup: ## Create database backup
@echo "$(BLUE)[INFO]$(NC) Creating database backup..."
@./scripts/docker/deploy.sh backup
@echo "$(GREEN)[SUCCESS]$(NC) Database backup created"
docker-help: ## Show Docker deployment help
@echo "$(BLUE)[INFO]$(NC) Docker deployment help:"
@./scripts/docker/deploy.sh --help
# Development shortcuts
config-validate: build ## Validate configuration files
@echo "$(BLUE)[INFO]$(NC) Validating configuration..."
@if [ -f $(CONFIG_PATH) ]; then \
echo "$(BLUE)[INFO]$(NC) Validating $(CONFIG_PATH)"; \
TANKSTOPP_CONFIG_PATH=$(CONFIG_PATH) $(BINARY_PATH) --validate-config 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) Configuration validation not yet implemented"; \
fi
@if [ -f $(CONFIG_DEV_PATH) ]; then \
echo "$(BLUE)[INFO]$(NC) Validating $(CONFIG_DEV_PATH)"; \
TANKSTOPP_CONFIG_PATH=$(CONFIG_DEV_PATH) $(BINARY_PATH) --validate-config 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) Configuration validation not yet implemented"; \
fi
@if [ -f $(CONFIG_PROD_PATH) ]; then \
echo "$(BLUE)[INFO]$(NC) Validating $(CONFIG_PROD_PATH)"; \
TANKSTOPP_CONFIG_PATH=$(CONFIG_PROD_PATH) $(BINARY_PATH) --validate-config 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) Configuration validation not yet implemented"; \
fi
@echo "$(GREEN)[SUCCESS]$(NC) Configuration validation completed"
config-show: ## Show current configuration (without secrets)
@echo "$(BLUE)[INFO]$(NC) Current configuration:"
@echo "Config files found:"
@if [ -f $(CONFIG_PATH) ]; then echo "$(CONFIG_PATH)"; else echo "$(CONFIG_PATH)"; fi
@if [ -f $(CONFIG_DEV_PATH) ]; then echo "$(CONFIG_DEV_PATH)"; else echo "$(CONFIG_DEV_PATH)"; fi
@if [ -f $(CONFIG_PROD_PATH) ]; then echo "$(CONFIG_PROD_PATH)"; else echo "$(CONFIG_PROD_PATH)"; fi
@echo ""
@echo "Environment variables:"
@env | grep -E '^TANKSTOPP_|^DB_|^ENV=' | sort || echo " No TankStopp environment variables set"
config-examples: ## Create example configuration files
@echo "$(BLUE)[INFO]$(NC) Creating example configuration files..."
@if [ ! -f $(CONFIG_PATH) ]; then \
echo "$(BLUE)[INFO]$(NC) Creating $(CONFIG_PATH)"; \
cp $(CONFIG_PATH) $(CONFIG_PATH).example 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) Default config not found"; \
fi
@if [ ! -f config.example.yaml ]; then \
echo "$(BLUE)[INFO]$(NC) Creating config.example.yaml"; \
cp $(CONFIG_PATH) config.example.yaml 2>/dev/null || echo "$(YELLOW)[WARNING]$(NC) Default config not found"; \
fi
@echo "$(GREEN)[SUCCESS]$(NC) Example configuration files created"
config-help: ## Show configuration documentation
@echo "$(BLUE)[INFO]$(NC) TankStopp Configuration Help"
@echo ""
@echo "Configuration Files:"
@echo " config.yaml - Default configuration"
@echo " config.development.yaml - Development environment"
@echo " config.production.yaml - Production environment"
@echo ""
@echo "Environment Variables (override config files):"
@echo " TANKSTOPP_CONFIG_PATH - Custom config file path"
@echo " TANKSTOPP_SERVER_PORT - Server port (default: 8081)"
@echo " TANKSTOPP_DATABASE_PATH - Database file path"
@echo " TANKSTOPP_APP_DEBUG - Enable debug mode (true/false)"
@echo " TANKSTOPP_APP_ENVIRONMENT - Environment (development/production/test)"
@echo ""
@echo "Legacy Environment Variables (still supported):"
@echo " DB_PATH - Database file path"
@echo " ENV - Environment name"
@echo ""
@echo "For complete documentation, see CONFIG_DOCUMENTATION.md"
run-dev: build ## Run in development mode with development config
@echo "$(BLUE)[INFO]$(NC) Running in development mode..."
@if [ -f $(CONFIG_DEV_PATH) ]; then \
TANKSTOPP_CONFIG_PATH=$(CONFIG_DEV_PATH) $(BINARY_PATH); \
else \
TANKSTOPP_APP_ENVIRONMENT=development $(BINARY_PATH); \
fi
run-prod: build ## Run in production mode with production config
@echo "$(BLUE)[INFO]$(NC) Running in production mode..."
@if [ -f $(CONFIG_PROD_PATH) ]; then \
TANKSTOPP_CONFIG_PATH=$(CONFIG_PROD_PATH) $(BINARY_PATH); \
else \
TANKSTOPP_APP_ENVIRONMENT=production TANKSTOPP_APP_DEBUG=false $(BINARY_PATH); \
fi
config-test: build ## Test configuration loading
@echo "$(BLUE)[INFO]$(NC) Testing configuration loading..."
@echo "Testing with default config:"
@timeout 3 $(BINARY_PATH) 2>&1 | head -5 || true
@echo ""
@if [ -f $(CONFIG_DEV_PATH) ]; then \
echo "Testing with development config:"; \
timeout 3 TANKSTOPP_CONFIG_PATH=$(CONFIG_DEV_PATH) $(BINARY_PATH) 2>&1 | head -5 || true; \
echo ""; \
fi
@echo "Testing with environment variables:"
@timeout 3 TANKSTOPP_SERVER_PORT=9999 TANKSTOPP_APP_DEBUG=true $(BINARY_PATH) 2>&1 | head -5 || true
d: dev ## Alias for dev
b: build ## Alias for build
t: test ## Alias for test
c: clean ## Alias for clean
r: run ## Alias for run
rd: run-dev ## Alias for run-dev
rp: run-prod ## Alias for run-prod
# Docker aliases
db: docker-build ## Alias for docker-build
dr: docker-run ## Alias for docker-run
ds: docker-stop ## Alias for docker-stop
dl: docker-logs ## Alias for docker-logs
dc: docker-clean ## Alias for docker-clean
dd: docker-deploy ## Alias for docker-deploy