# 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