pg-api 0.1.0

A high-performance PostgreSQL REST API driver with rate limiting, connection pooling, and observability
# PostgreSQL API Service Makefile
# Build, test, and deployment automation

# Variables
BINARY_NAME = pg-api
VERSION = $(shell cat VERSION 2>/dev/null || echo "0.1.0")
BUILD_DATE = $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
GIT_COMMIT = $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
RUST_VERSION = $(shell rustc --version | cut -d' ' -f2)

# Paths
INSTALL_PATH ?= /opt/prod/pg-api
BUILD_DIR = target
RELEASE_DIR = $(BUILD_DIR)/release
DEBUG_DIR = $(BUILD_DIR)/debug
DIST_DIR = dist

# Rust flags
RUSTFLAGS = -C link-arg=-s
CARGO = cargo

# Colors for output
COLOR_RESET = \033[0m
COLOR_BOLD = \033[1m
COLOR_GREEN = \033[32m
COLOR_YELLOW = \033[33m
COLOR_BLUE = \033[34m
COLOR_RED = \033[31m

# Default target
.DEFAULT_GOAL := help

# Phony targets
.PHONY: all build build-release test clean install uninstall package help version check lint fmt security-audit run dev setup-dev

## Help target
help: ## Show this help message
	@echo "$(COLOR_BOLD)PostgreSQL API Service - Makefile$(COLOR_RESET)"
	@echo "$(COLOR_BLUE)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$(COLOR_RESET)"
	@echo ""
	@echo "$(COLOR_BOLD)Usage:$(COLOR_RESET)"
	@echo "  make $(COLOR_GREEN)<target>$(COLOR_RESET)"
	@echo ""
	@echo "$(COLOR_BOLD)Available targets:$(COLOR_RESET)"
	@awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*?##/ { printf "  $(COLOR_GREEN)%-15s$(COLOR_RESET) %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
	@echo ""
	@echo "$(COLOR_BOLD)Examples:$(COLOR_RESET)"
	@echo "  $(COLOR_YELLOW)make build$(COLOR_RESET)        # Build debug binary"
	@echo "  $(COLOR_YELLOW)make release$(COLOR_RESET)      # Build optimized release binary"
	@echo "  $(COLOR_YELLOW)make test$(COLOR_RESET)         # Run all tests"
	@echo "  $(COLOR_YELLOW)make package$(COLOR_RESET)      # Create distribution package"
	@echo ""
	@echo "$(COLOR_BOLD)Version:$(COLOR_RESET) $(VERSION)"
	@echo "$(COLOR_BOLD)Commit:$(COLOR_RESET) $(GIT_COMMIT)"

## Development targets
all: lint test build ## Run lint, test, and build

build: ## Build debug binary
	@echo "$(COLOR_BLUE)Building debug binary...$(COLOR_RESET)"
	@$(CARGO) build
	@echo "$(COLOR_GREEN)✓ Debug build complete: $(DEBUG_DIR)/$(BINARY_NAME)$(COLOR_RESET)"

release: ## Build optimized release binary
	@echo "$(COLOR_BLUE)Building release binary...$(COLOR_RESET)"
	@RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build --release
	@echo "$(COLOR_GREEN)✓ Release build complete: $(RELEASE_DIR)/$(BINARY_NAME)$(COLOR_RESET)"
	@ls -lh $(RELEASE_DIR)/$(BINARY_NAME)

dev: ## Run in development mode
	@echo "$(COLOR_BLUE)Starting development server...$(COLOR_RESET)"
	@RUST_LOG=debug $(CARGO) run

run: build ## Build and run debug binary
	@echo "$(COLOR_BLUE)Running debug binary...$(COLOR_RESET)"
	@RUST_LOG=info $(DEBUG_DIR)/$(BINARY_NAME)

## Testing targets
test: ## Run all tests
	@echo "$(COLOR_BLUE)Running tests...$(COLOR_RESET)"
	@$(CARGO) test --all-features
	@echo "$(COLOR_GREEN)✓ All tests passed$(COLOR_RESET)"

test-verbose: ## Run tests with verbose output
	@echo "$(COLOR_BLUE)Running tests (verbose)...$(COLOR_RESET)"
	@$(CARGO) test --all-features -- --nocapture

test-single: ## Run a single test (use TEST=test_name)
	@echo "$(COLOR_BLUE)Running test: $(TEST)$(COLOR_RESET)"
	@$(CARGO) test $(TEST) -- --nocapture

bench: ## Run benchmarks
	@echo "$(COLOR_BLUE)Running benchmarks...$(COLOR_RESET)"
	@$(CARGO) bench

## Code quality targets
check: ## Fast compilation check without building
	@echo "$(COLOR_BLUE)Checking code...$(COLOR_RESET)"
	@$(CARGO) check --all-features
	@echo "$(COLOR_GREEN)✓ Code check complete$(COLOR_RESET)"

lint: ## Run clippy linter
	@echo "$(COLOR_BLUE)Running clippy...$(COLOR_RESET)"
	@$(CARGO) clippy -- -D warnings
	@echo "$(COLOR_GREEN)✓ Linting complete$(COLOR_RESET)"

fmt: ## Format code with rustfmt
	@echo "$(COLOR_BLUE)Formatting code...$(COLOR_RESET)"
	@$(CARGO) fmt
	@echo "$(COLOR_GREEN)✓ Code formatted$(COLOR_RESET)"

fmt-check: ## Check code formatting
	@echo "$(COLOR_BLUE)Checking code format...$(COLOR_RESET)"
	@$(CARGO) fmt -- --check
	@echo "$(COLOR_GREEN)✓ Code format check complete$(COLOR_RESET)"

security-audit: ## Run security audit on dependencies
	@echo "$(COLOR_BLUE)Running security audit...$(COLOR_RESET)"
	@cargo audit || (echo "$(COLOR_YELLOW)Install cargo-audit with: cargo install cargo-audit$(COLOR_RESET)" && exit 1)
	@echo "$(COLOR_GREEN)✓ Security audit complete$(COLOR_RESET)"

## Installation targets
install: release ## Install to system (requires sudo)
	@echo "$(COLOR_BLUE)Installing pg-api...$(COLOR_RESET)"
	@if [ ! -f setup.py ]; then \
		echo "$(COLOR_RED)Error: setup.py not found$(COLOR_RESET)"; \
		exit 1; \
	fi
	@sudo python3 setup.py --non-interactive --action install --install-path $(INSTALL_PATH)
	@echo "$(COLOR_GREEN)✓ Installation complete$(COLOR_RESET)"

uninstall: ## Uninstall from system (requires sudo)
	@echo "$(COLOR_BLUE)Uninstalling pg-api...$(COLOR_RESET)"
	@if [ ! -f setup.py ]; then \
		echo "$(COLOR_RED)Error: setup.py not found$(COLOR_RESET)"; \
		exit 1; \
	fi
	@sudo python3 setup.py --non-interactive --action uninstall --install-path $(INSTALL_PATH)
	@echo "$(COLOR_GREEN)✓ Uninstallation complete$(COLOR_RESET)"

## Packaging targets
package: release ## Create distribution package
	@echo "$(COLOR_BLUE)Creating distribution package...$(COLOR_RESET)"
	@mkdir -p $(DIST_DIR)
	@# Create package directory
	@rm -rf $(DIST_DIR)/pg-api-$(VERSION)
	@mkdir -p $(DIST_DIR)/pg-api-$(VERSION)
	@# Copy files
	@cp -r src Cargo.toml Cargo.lock setup.py Makefile VERSION LICENSE.md CHANGELOG.md roadmap.md $(DIST_DIR)/pg-api-$(VERSION)/ 2>/dev/null || true
	@cp -r config $(DIST_DIR)/pg-api-$(VERSION)/
	@mkdir -p $(DIST_DIR)/pg-api-$(VERSION)/target/release
	@cp $(RELEASE_DIR)/$(BINARY_NAME) $(DIST_DIR)/pg-api-$(VERSION)/target/release/
	@# Create tarball
	@cd $(DIST_DIR) && tar -czf pg-api-$(VERSION).tar.gz pg-api-$(VERSION)
	@rm -rf $(DIST_DIR)/pg-api-$(VERSION)
	@echo "$(COLOR_GREEN)✓ Package created: $(DIST_DIR)/pg-api-$(VERSION).tar.gz$(COLOR_RESET)"
	@ls -lh $(DIST_DIR)/pg-api-$(VERSION).tar.gz

dist: package ## Alias for package

## Utility targets
clean: ## Clean build artifacts
	@echo "$(COLOR_BLUE)Cleaning build artifacts...$(COLOR_RESET)"
	@$(CARGO) clean
	@rm -rf $(DIST_DIR)
	@echo "$(COLOR_GREEN)✓ Clean complete$(COLOR_RESET)"

version: ## Display version information
	@echo "$(COLOR_BOLD)Version Information:$(COLOR_RESET)"
	@echo "  pg-api:     $(VERSION)"
	@echo "  Git commit: $(GIT_COMMIT)"
	@echo "  Build date: $(BUILD_DATE)"
	@echo "  Rust:       $(RUST_VERSION)"

setup-dev: ## Setup development environment
	@echo "$(COLOR_BLUE)Setting up development environment...$(COLOR_RESET)"
	@# Install Rust if not present
	@if ! command -v rustc > /dev/null; then \
		echo "$(COLOR_YELLOW)Installing Rust...$(COLOR_RESET)"; \
		curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; \
		. $$HOME/.cargo/env; \
	fi
	@# Install development tools
	@echo "$(COLOR_BLUE)Installing development tools...$(COLOR_RESET)"
	@cargo install cargo-watch cargo-audit || true
	@# Install pre-commit hooks
	@if [ -d .git ]; then \
		echo "#!/bin/sh" > .git/hooks/pre-commit; \
		echo "make fmt-check" >> .git/hooks/pre-commit; \
		echo "make lint" >> .git/hooks/pre-commit; \
		chmod +x .git/hooks/pre-commit; \
		echo "$(COLOR_GREEN)✓ Pre-commit hooks installed$(COLOR_RESET)"; \
	fi
	@echo "$(COLOR_GREEN)✓ Development environment ready$(COLOR_RESET)"

## Docker targets (optional)
docker-build: ## Build Docker image
	@echo "$(COLOR_BLUE)Building Docker image...$(COLOR_RESET)"
	@docker build -t pg-api:$(VERSION) -t pg-api:latest .
	@echo "$(COLOR_GREEN)✓ Docker image built: pg-api:$(VERSION)$(COLOR_RESET)"

docker-run: ## Run Docker container
	@echo "$(COLOR_BLUE)Running Docker container...$(COLOR_RESET)"
	@docker run -d \
		--name pg-api \
		-p 8080:8080 \
		-v $(PWD)/config:/opt/pg-api/config \
		--env-file .env \
		pg-api:latest
	@echo "$(COLOR_GREEN)✓ Container started: pg-api$(COLOR_RESET)"

## Database targets
db-setup: ## Setup PostgreSQL database
	@echo "$(COLOR_BLUE)Setting up PostgreSQL database...$(COLOR_RESET)"
	@if [ -f setup.py ]; then \
		sudo python3 setup.py --action check; \
	else \
		echo "$(COLOR_RED)Error: setup.py not found$(COLOR_RESET)"; \
		exit 1; \
	fi

db-migrate: ## Run database migrations
	@echo "$(COLOR_BLUE)Running database migrations...$(COLOR_RESET)"
	@if [ -d migrations ]; then \
		for file in migrations/*.sql; do \
			echo "  Applying: $$file"; \
			psql -h localhost -U postgres -f $$file; \
		done; \
		echo "$(COLOR_GREEN)✓ Migrations complete$(COLOR_RESET)"; \
	else \
		echo "$(COLOR_YELLOW)No migrations found$(COLOR_RESET)"; \
	fi

## Service management
service-start: ## Start pg-api service
	@echo "$(COLOR_BLUE)Starting pg-api service...$(COLOR_RESET)"
	@sudo systemctl start pg-api
	@echo "$(COLOR_GREEN)✓ Service started$(COLOR_RESET)"

service-stop: ## Stop pg-api service
	@echo "$(COLOR_BLUE)Stopping pg-api service...$(COLOR_RESET)"
	@sudo systemctl stop pg-api
	@echo "$(COLOR_GREEN)✓ Service stopped$(COLOR_RESET)"

service-restart: ## Restart pg-api service
	@echo "$(COLOR_BLUE)Restarting pg-api service...$(COLOR_RESET)"
	@sudo systemctl restart pg-api
	@echo "$(COLOR_GREEN)✓ Service restarted$(COLOR_RESET)"

service-status: ## Show pg-api service status
	@sudo systemctl status pg-api

service-logs: ## Show pg-api service logs
	@sudo journalctl -u pg-api -f

## Release management
release-patch: ## Create patch release (x.x.N+1)
	@echo "$(COLOR_BLUE)Creating patch release...$(COLOR_RESET)"
	@./scripts/release.sh patch

release-minor: ## Create minor release (x.N+1.0)
	@echo "$(COLOR_BLUE)Creating minor release...$(COLOR_RESET)"
	@./scripts/release.sh minor

release-major: ## Create major release (N+1.0.0)
	@echo "$(COLOR_BLUE)Creating major release...$(COLOR_RESET)"
	@./scripts/release.sh major

# Include local overrides if they exist
-include Makefile.local