.PHONY: all build test test-unit test-integration lint coverage clean install help docker-up docker-down docker-test docker-test-integration start stop release release-version # Binary name BINARY_NAME=relspec # Build directory BUILD_DIR=build # Go parameters GOCMD=go GOBUILD=$(GOCMD) build GOTEST=$(GOCMD) test GOGET=$(GOCMD) get GOMOD=$(GOCMD) mod GOCLEAN=$(GOCMD) clean # Auto-detect container runtime (Docker or Podman) CONTAINER_RUNTIME := $(shell \ if command -v podman > /dev/null 2>&1; then \ echo "podman"; \ elif command -v docker > /dev/null 2>&1; then \ echo "docker"; \ else \ echo "none"; \ fi) # Detect compose command COMPOSE_CMD := $(shell \ if [ "$(CONTAINER_RUNTIME)" = "podman" ]; then \ echo "podman-compose"; \ elif command -v docker-compose > /dev/null 2>&1; then \ echo "docker-compose"; \ else \ echo "docker compose"; \ fi) all: lint test build ## Run linting, tests, and build build: deps ## Build the binary @echo "Building $(BINARY_NAME)..." @mkdir -p $(BUILD_DIR) $(GOBUILD) -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/relspec @echo "Build complete: $(BUILD_DIR)/$(BINARY_NAME)" test: test-unit ## Run all unit tests (alias for test-unit) test-unit: ## Run unit tests (excludes integration tests) @echo "Running unit tests..." $(GOTEST) -v -race -coverprofile=coverage.out -covermode=atomic $$(go list ./... | grep -v '/tests/integration' | grep -v '/tests/assets' | grep -v '/pkg/readers/pgsql') test-integration: ## Run integration tests (requires RELSPEC_TEST_PG_CONN environment variable) @echo "Running integration tests..." @if [ -z "$$RELSPEC_TEST_PG_CONN" ]; then \ echo "Error: RELSPEC_TEST_PG_CONN environment variable is not set"; \ echo "Example: export RELSPEC_TEST_PG_CONN='postgres://relspec:relspec_test_password@localhost:5439/relspec_test'"; \ exit 1; \ fi @echo "Running PostgreSQL reader tests..." $(GOTEST) -v -count=1 ./pkg/readers/pgsql/ @echo "Running general integration tests..." $(GOTEST) -v -count=1 ./tests/integration/ coverage: test ## Run tests with coverage report @echo "Generating coverage report..." $(GOCMD) tool cover -html=coverage.out -o coverage.html @echo "Coverage report generated: coverage.html" lint: ## Run linter @echo "Running linter..." @if command -v golangci-lint > /dev/null; then \ golangci-lint run --config=.golangci.json; \ else \ echo "golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \ exit 1; \ fi lintfix: ## Run linter @echo "Running linter..." @if command -v golangci-lint > /dev/null; then \ golangci-lint run --config=.golangci.json --fix; \ else \ echo "golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \ exit 1; \ fi clean: ## Clean build artifacts @echo "Cleaning..." $(GOCLEAN) rm -rf $(BUILD_DIR) rm -f coverage.out coverage.html @echo "Clean complete" install: ## Install the binary to $GOPATH/bin @echo "Installing $(BINARY_NAME)..." $(GOCMD) install ./cmd/relspec @echo "Install complete" deps: ## Download dependencies @echo "Downloading dependencies..." $(GOMOD) download $(GOMOD) tidy @echo "Dependencies updated" start: docker-up ## Alias for docker-up (start PostgreSQL test database) stop: docker-down ## Alias for docker-down (stop PostgreSQL test database) docker-up: ## Start PostgreSQL test database @echo "Starting PostgreSQL test database (using $(CONTAINER_RUNTIME))..." @if [ "$(CONTAINER_RUNTIME)" = "none" ]; then \ echo "Error: Neither Docker nor Podman is installed"; \ exit 1; \ fi @if [ "$(CONTAINER_RUNTIME)" = "podman" ]; then \ podman run -d --name relspec-test-postgres \ -e POSTGRES_USER=relspec \ -e POSTGRES_PASSWORD=relspec_test_password \ -e POSTGRES_DB=relspec_test \ -p 5439:5432 \ -v ./tests/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:Z \ postgres:16-alpine 2>/dev/null || echo "Container already running"; \ else \ $(COMPOSE_CMD) up -d postgres; \ fi @echo "Waiting for PostgreSQL to be ready..." @sleep 3 @echo "PostgreSQL is running on port 5439" @echo "Connection: postgres://relspec:relspec_test_password@localhost:5439/relspec_test" docker-down: ## Stop PostgreSQL test database @echo "Stopping PostgreSQL test database (using $(CONTAINER_RUNTIME))..." @if [ "$(CONTAINER_RUNTIME)" = "podman" ]; then \ podman stop relspec-test-postgres 2>/dev/null || true; \ podman rm relspec-test-postgres 2>/dev/null || true; \ else \ $(COMPOSE_CMD) down; \ fi @echo "PostgreSQL stopped" docker-test: ## Run PostgreSQL integration tests with Docker/Podman @if [ "$(CONTAINER_RUNTIME)" = "podman" ]; then \ ./tests/postgres/run_tests_podman.sh; \ else \ ./tests/postgres/run_tests.sh; \ fi docker-test-integration: docker-up ## Start DB and run integration tests @echo "Running integration tests..." @sleep 2 @RELSPEC_TEST_PG_CONN="postgres://relspec:relspec_test_password@localhost:5439/relspec_test" \ $(GOTEST) -v ./pkg/readers/pgsql/ -count=1 || (make docker-down && exit 1) @make docker-down release: ## Create and push a new release tag (auto-increments patch version) @echo "Creating new release..." @latest_tag=$$(git describe --tags --abbrev=0 2>/dev/null || echo ""); \ if [ -z "$$latest_tag" ]; then \ version="v1.0.0"; \ echo "No existing tags found. Creating first release: $$version"; \ commit_logs=$$(git log --pretty=format:"- %s" --no-merges); \ else \ echo "Latest tag: $$latest_tag"; \ version_number=$${latest_tag#v}; \ IFS='.' read -r major minor patch <<< "$$version_number"; \ patch=$$((patch + 1)); \ version="v$$major.$$minor.$$patch"; \ echo "Creating new release: $$version"; \ commit_logs=$$(git log "$${latest_tag}..HEAD" --pretty=format:"- %s" --no-merges); \ fi; \ if [ -z "$$commit_logs" ]; then \ tag_message="Release $$version"; \ else \ tag_message="Release $$version\n\n$$commit_logs"; \ fi; \ git tag -a "$$version" -m "$$tag_message"; \ git push origin "$$version"; \ echo "Tag $$version created and pushed to remote repository." release-version: ## Create and push a release with specific version (use: make release-version VERSION=v1.2.3) @if [ -z "$(VERSION)" ]; then \ echo "Error: VERSION is required. Usage: make release-version VERSION=v1.2.3"; \ exit 1; \ fi @version="$(VERSION)"; \ if ! echo "$$version" | grep -q "^v"; then \ version="v$$version"; \ fi; \ echo "Creating release: $$version"; \ latest_tag=$$(git describe --tags --abbrev=0 2>/dev/null || echo ""); \ if [ -z "$$latest_tag" ]; then \ commit_logs=$$(git log --pretty=format:"- %s" --no-merges); \ else \ commit_logs=$$(git log "$${latest_tag}..HEAD" --pretty=format:"- %s" --no-merges); \ fi; \ if [ -z "$$commit_logs" ]; then \ tag_message="Release $$version"; \ else \ tag_message="Release $$version\n\n$$commit_logs"; \ fi; \ git tag -a "$$version" -m "$$tag_message"; \ git push origin "$$version"; \ echo "Tag $$version created and pushed to remote repository." help: ## Display this help screen @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'