Skip to content

Instantly share code, notes, and snippets.

@crazywolf132
Last active December 3, 2024 09:14
Show Gist options
  • Save crazywolf132/5d6f79b6cc0cb4426d641f068da81613 to your computer and use it in GitHub Desktop.
Save crazywolf132/5d6f79b6cc0cb4426d641f068da81613 to your computer and use it in GitHub Desktop.
Ultimate Golang Makefile for any project

Ultimate Golang Makefile

A comprehensive, production-ready Makefile system for Go projects of any size. This Makefile provides a complete set of commands for development, testing, building, and deployment workflows while remaining flexible and customizable.

πŸš€ Features

  • Flexible Configuration: Support for environment variables, .env files, and command-line overrides
  • Multi-Environment Support: Development, staging, and production builds
  • Cross-Platform Building: Support for multiple OS/Architecture combinations
  • Advanced Testing: Unit, integration, and end-to-end testing with coverage reports
  • Docker Integration: Build, push, and run Docker containers
  • Database Operations: Migration management and database utilities
  • Development Tools: Hot reload, formatting, linting, and security scanning
  • CI/CD Ready: Integrated pipeline support for common CI systems
  • Documentation: Automatic API documentation generation
  • Monorepo Support: Build and manage multiple services
  • Comprehensive Reporting: Test coverage, benchmarks, and security reports

πŸ“‹ Prerequisites

  • Go 1.21 or higher
  • Make
  • Docker (optional)
  • Git

πŸ›  Installation

  1. Copy the Makefile to your project root:
curl -O https://gist.githubusercontent.com/crazywolf132/5d6f79b6cc0cb4426d641f068da81613/raw/78d002f24e5bbc2c6fef2cfe231007baac78923c/Makefile
  1. Initialize your project:
make init

This will:

  • Create necessary directories
  • Initialize Go modules
  • Install required tools
  • Create default configuration files

βš™οΈ Configuration

Environment Variables

Create a .env file in your project root to override default settings:

# Project Configuration
PROJECT_NAME=myapp
ORGANIZATION=myorg
ENABLE_DOCKER=true
ENABLE_PROTO=false

# Build Settings
CGO_ENABLED=0
COVERAGE_THRESHOLD=80

# Docker Settings
DOCKER_REGISTRY=docker.io
DOCKER_REPO=myorg/myapp

Project Structure

The Makefile assumes the following project structure:

.
β”œβ”€β”€ cmd/
β”‚   └── myapp/
β”‚       └── main.go
β”œβ”€β”€ pkg/
β”œβ”€β”€ internal/
β”œβ”€β”€ api/
β”œβ”€β”€ docs/
β”œβ”€β”€ scripts/
β”œβ”€β”€ build/
β”œβ”€β”€ configs/
β”œβ”€β”€ test/
β”‚   β”œβ”€β”€ e2e/
β”‚   └── integration/
└── Makefile

🎯 Common Commands

Development

# Start development with hot reload
make dev

# Run tests
make test

# Run tests with coverage
make test-coverage

# Format and lint code
make fmt lint

# Generate mocks and protobuf
make generate

Building

# Build for current platform
make build

# Build for all platforms
make build-all

# Build with debug symbols
make build-debug

# Build with race detector
make build-race

Docker Operations

# Build Docker image
make docker-build

# Push Docker image
make docker-push

# Run in Docker container
make docker-run

Database Operations

# Run migrations
make db-migrate

# Rollback last migration
make db-rollback

# Reset database
make db-reset

Maintenance

# Install/update dependencies
make deps
make deps-update

# Clean build artifacts
make clean

# Update tools
make tools

πŸ—οΈ Project Types

Basic Project

For single-service projects, use default settings:

PROJECT_TYPE=basic

Monorepo

For multiple services, configure as follows:

PROJECT_TYPE=monorepo
MONOREPO_SERVICES=service1 service2 service3

Directory structure for monorepo:

.
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ service1/
β”‚   β”‚   └── cmd/
β”‚   β”œβ”€β”€ service2/
β”‚   β”‚   └── cmd/
β”‚   └── service3/
β”‚       └── cmd/
└── Makefile

πŸ“Š Reports

Generate comprehensive project reports:

make report

This creates:

  • Test coverage reports
  • Benchmark results
  • Linting reports
  • Security scan results

Reports are saved in docs/reports/.

πŸ”„ CI/CD Integration

The Makefile includes predefined CI/CD targets:

# Run CI pipeline
make ci

# Run CD pipeline
make cd

Customize pipelines by modifying these targets in the Makefile.

πŸ“š Documentation

# Generate documentation
make docs

# Serve documentation locally
make serve-docs

🎨 Customization

Adding New Targets

Add custom targets at the end of the Makefile:

.PHONY: custom-target
custom-target: ## Custom target description
    @echo "Running custom target..."
    @# Custom commands here

Modifying Existing Targets

Override existing targets by redefining them in config.mk:

# config.mk
.PHONY: test
test: ## Custom test implementation
    @echo "Running custom tests..."
    @# Custom test commands

🀝 Contributing

Leave comments below, and we will make iterative improvements over time

πŸ“œ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgements

Special thanks to the Go community and all contributors who have helped shape this Makefile system.

# =============================================================================
# πŸ“š Documentation
# =============================================================================
# This Makefile is designed to support Go projects of any size, from small
# personal projects to large enterprise applications. It provides a comprehensive
# set of targets for development, testing, building, and deployment.
#
# Quick Start:
# 1. Copy this Makefile to your project
# 2. Create a .env file for local overrides (optional)
# 3. Run `make init` to initialize the project
# 4. Run `make help` to see available commands
#
# Configuration:
# The Makefile can be configured in several ways (in order of precedence):
# 1. Command line variables: make build GOOS=darwin
# 2. Environment variables: export GOOS=darwin
# 3. .env file in project root
# 4. Default values in this Makefile
#
# For large projects:
# - Create a config/ directory with environment-specific configs
# - Use config.mk files for project-specific settings
# - Enable build caching and parallel builds
# - Set up CI/CD pipeline configurations
#
# For small projects:
# - Use default configurations
# - Disable unused features in .env file
# - Focus on core development commands
# =============================================================================
# πŸ”„ Load Environment & Configs
# =============================================================================
# Load .env file if it exists
ifneq (,$(wildcard .env))
include .env
export
endif
# Load project-specific config if it exists
ifneq (,$(wildcard config.mk))
include config.mk
endif
# =============================================================================
# 🎯 Project Configuration
# =============================================================================
# Project Settings
PROJECT_NAME ?= myapp
ORGANIZATION ?= myorg
DESCRIPTION ?= "My Awesome Go Project"
MAINTAINER ?= "[email protected]"
# Feature Flags (can be disabled in .env)
ENABLE_DOCKER ?= true
ENABLE_PROTO ?= true
ENABLE_DOCS ?= true
ENABLE_SECURITY_SCAN ?= true
ENABLE_ADVANCED_TESTING ?= true
ENABLE_BUILD_CACHE ?= true
# Project Structure
PROJECT_TYPE ?= basic # basic, monorepo, microservices
MONOREPO_SERVICES ?= $(wildcard services/*)
BUILD_TARGETS ?= $(if $(filter monorepo,$(PROJECT_TYPE)),$(MONOREPO_SERVICES),$(PROJECT_NAME))
# Build Settings
BUILD_SYSTEM ?= local # local, ci
CI_SYSTEM ?= github # github, gitlab, jenkins
PARALLEL_JOBS ?= $(shell nproc)
ENABLE_PARALLEL := $(if $(filter local,$(BUILD_SYSTEM)),true,false)
# Version Control
VERSION_STRATEGY ?= git # git, semver, date
VERSION := $(shell \
if [ "$(VERSION_STRATEGY)" = "git" ]; then \
git describe --tags --always --dirty; \
elif [ "$(VERSION_STRATEGY)" = "semver" ]; then \
cat VERSION 2>/dev/null || echo "0.1.0"; \
else \
date -u '+%Y%m%d-%H%M%S'; \
fi)
GIT_COMMIT ?= $(shell git rev-parse --short HEAD)
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
BUILD_TIME ?= $(shell date -u '+%Y-%m-%d_%H:%M:%S')
BUILD_BY ?= $(shell whoami)
# Go Configuration
GO ?= go
GOCMD = $(shell which go)
GOPATH ?= $(shell $(GO) env GOPATH)
GOBIN ?= $(GOPATH)/bin
GOOS ?= $(shell $(GO) env GOOS)
GOARCH ?= $(shell $(GO) env GOARCH)
CGO_ENABLED ?= 0
# Tools & Linters
GOLANGCI_LINT ?= $(GOBIN)/golangci-lint
GOFUMPT ?= $(GOBIN)/gofumpt
GODOC ?= $(GOBIN)/godoc
GOVULNCHECK ?= $(GOBIN)/govulncheck
MOCKGEN ?= $(GOBIN)/mockgen
AIR ?= $(GOBIN)/air
# Directories
ROOT_DIR ?= $(shell pwd)
BIN_DIR ?= $(ROOT_DIR)/bin
DIST_DIR ?= $(ROOT_DIR)/dist
DOCS_DIR ?= $(ROOT_DIR)/docs
TOOLS_DIR ?= $(ROOT_DIR)/tools
PROTO_DIR ?= $(ROOT_DIR)/proto
CONFIG_DIR ?= $(ROOT_DIR)/configs
SCRIPTS_DIR ?= $(ROOT_DIR)/scripts
MIGRATIONS_DIR ?= $(ROOT_DIR)/migrations
# Source Files
GOFILES = $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./.git/*")
GOPACKAGES = $(shell $(GO) list ./... | grep -v /vendor/)
# Build Configuration
BUILD_TAGS ?=
EXTRA_TAGS ?=
ALL_TAGS = $(BUILD_TAGS) $(EXTRA_TAGS)
# Linker Flags
LD_FLAGS += -s -w
LD_FLAGS += -X '$(shell go list -m)/pkg/version.Version=$(VERSION)'
LD_FLAGS += -X '$(shell go list -m)/pkg/version.Commit=$(GIT_COMMIT)'
LD_FLAGS += -X '$(shell go list -m)/pkg/version.Branch=$(GIT_BRANCH)'
LD_FLAGS += -X '$(shell go list -m)/pkg/version.BuildTime=$(BUILD_TIME)'
LD_FLAGS += -X '$(shell go list -m)/pkg/version.BuildBy=$(BUILD_BY)'
# Performance & Debug Flags
GCFLAGS ?=
ASMFLAGS ?=
# Docker Configuration
DOCKER_REGISTRY ?= docker.io
DOCKER_REPO ?= $(ORGANIZATION)/$(PROJECT_NAME)
DOCKER_IMAGE ?= $(DOCKER_REGISTRY)/$(DOCKER_REPO)
DOCKER_TAG ?= $(VERSION)
DOCKERFILE ?= Dockerfile
DOCKER_BUILD_ARGS ?=
DOCKER_BUILD_CONTEXT ?= .
# Test Configuration
TEST_TIMEOUT ?= 5m
TEST_FLAGS ?= -v -race -cover
COVERAGE_OUT ?= coverage.out
COVERAGE_HTML ?= coverage.html
COVERAGE_THRESHOLD ?= 80
BENCH_FLAGS ?= -benchmem
BENCH_TIME ?= 2s
TEST_PATTERN ?= .
SKIP_PATTERN ?=
# Cross-Compilation Targets
PLATFORMS ?= \
linux/amd64/- \
linux/arm64/- \
linux/arm/7 \
darwin/amd64/- \
darwin/arm64/- \
windows/amd64/- \
windows/arm64/-
# =============================================================================
# 🎨 Terminal Colors & Emoji
# =============================================================================
# Colors
BLUE := \033[34m
GREEN := \033[32m
YELLOW := \033[33m
RED := \033[31m
MAGENTA := \033[35m
CYAN := \033[36m
WHITE := \033[37m
BOLD := \033[1m
RESET := \033[0m
# Status Indicators
INFO := @printf "$(BLUE)ℹ️ $(RESET)"
SUCCESS := @printf "$(GREEN)βœ… $(RESET)"
WARN := @printf "$(YELLOW)⚠️ $(RESET)"
ERROR := @printf "$(RED)❌ $(RESET)"
WORKING := @printf "$(CYAN)πŸ”¨ $(RESET)"
DEBUG := @printf "$(MAGENTA)πŸ” $(RESET)"
ROCKET := @printf "$(GREEN)πŸš€ $(RESET)"
PACKAGE := @printf "$(CYAN)πŸ“¦ $(RESET)"
TRASH := @printf "$(YELLOW)πŸ—‘οΈ $(RESET)"
# =============================================================================
# 🎯 Core Build System
# =============================================================================
.PHONY: init
init: ## Initialize project with sensible defaults
$(INFO) Initializing project...
@if [ ! -f "go.mod" ]; then \
$(GO) mod init $(shell basename $(CURDIR)); \
fi
@if [ ! -f ".env" ]; then \
echo "# Project Configuration" > .env; \
echo "PROJECT_NAME=$(PROJECT_NAME)" >> .env; \
echo "ENABLE_DOCKER=true" >> .env; \
echo "ENABLE_PROTO=false" >> .env; \
fi
@if [ ! -f ".gitignore" ]; then \
curl -sL https://www.gitignore.io/api/go > .gitignore; \
fi
@mkdir -p cmd pkg internal api docs scripts build configs
$(MAKE) deps
$(SUCCESS) Project initialized!
.PHONY: build
build: $(BIN_DIR) ## Build all targets
$(WORKING) Building project...
@$(foreach target,$(BUILD_TARGETS),\
$(MAKE) build-target TARGET=$(target) $(if $(filter true,$(ENABLE_PARALLEL)),--jobs=$(PARALLEL_JOBS)) &)
@wait
$(SUCCESS) Build complete!
.PHONY: build-target
build-target: generate
$(INFO) Building $(TARGET)...
@if [ -f "$(TARGET)/Makefile" ]; then \
$(MAKE) -C $(TARGET) build; \
else \
CGO_ENABLED=$(CGO_ENABLED) \
$(GO) build -tags '$(ALL_TAGS)' \
$(if $(filter true,$(ENABLE_BUILD_CACHE)),-x) \
-ldflags '$(LD_FLAGS)' \
-gcflags '$(GCFLAGS)' \
-asmflags '$(ASMFLAGS)' \
-o $(BIN_DIR)/$(notdir $(TARGET)) \
./$(if $(filter monorepo,$(PROJECT_TYPE)),$(TARGET)/cmd,cmd)/$(notdir $(TARGET)); \
fi
.PHONY: install
install: build ## Install the application
$(WORKING) Installing $(PROJECT_NAME)...
$(GO) install -tags '$(ALL_TAGS)' -ldflags '$(LD_FLAGS)' ./cmd/$(PROJECT_NAME)
$(SUCCESS) Installation complete!
# =============================================================================
# πŸ”„ Development Workflow
# =============================================================================
.PHONY: dev
dev: deps generate ## Start development environment
$(INFO) Starting development environment...
@if [ ! -f ".air.toml" ]; then \
cp $(CONFIG_DIR)/air.toml.example .air.toml 2>/dev/null || \
curl -sL https://raw.githubusercontent.com/cosmtrek/air/master/air.conf.example > .air.toml; \
fi
$(ROCKET) Running with hot reload...
$(AIR) -c .air.toml
.PHONY: run
run: build ## Run the application
$(ROCKET) Running $(PROJECT_NAME)...
$(BIN_DIR)/$(PROJECT_NAME)
.PHONY: generate
generate: ## Run code generation
$(WORKING) Running code generation...
$(GO) generate ./...
@if [ -n "$(wildcard $(PROTO_DIR)/*.proto)" ]; then \
$(MAKE) proto; \
fi
$(SUCCESS) Generation complete!
# =============================================================================
# πŸ§ͺ Testing & Quality
# =============================================================================
.PHONY: test
test: ## Run tests
$(INFO) Running tests...
$(GO) test $(TEST_FLAGS) \
-timeout $(TEST_TIMEOUT) \
-run '$(TEST_PATTERN)' \
$(if $(SKIP_PATTERN),-skip '$(SKIP_PATTERN)') \
./...
.PHONY: test-coverage
test-coverage: ## Run tests with coverage
$(INFO) Running tests with coverage...
$(GO) test $(TEST_FLAGS) \
-timeout $(TEST_TIMEOUT) \
-coverprofile=$(COVERAGE_OUT) \
./...
$(GO) tool cover -html=$(COVERAGE_OUT) -o $(COVERAGE_HTML)
@coverage=$$(go tool cover -func=$(COVERAGE_OUT) | grep total | awk '{print $$3}' | sed 's/%//'); \
if [ "$${coverage%.*}" -lt "$(COVERAGE_THRESHOLD)" ]; then \
$(ERROR) "Coverage $${coverage}% is below threshold $(COVERAGE_THRESHOLD)%"; \
exit 1; \
fi
$(SUCCESS) Coverage report generated: $(COVERAGE_HTML)
.PHONY: test-integration
test-integration: ## Run integration tests
$(INFO) Running integration tests...
$(GO) test $(TEST_FLAGS) \
-tags=integration \
-timeout $(TEST_TIMEOUT) \
./...
.PHONY: test-e2e
test-e2e: ## Run end-to-end tests
$(INFO) Running end-to-end tests...
$(GO) test $(TEST_FLAGS) \
-tags=e2e \
-timeout $(TEST_TIMEOUT) \
./test/e2e/...
.PHONY: bench
bench: ## Run benchmarks
$(INFO) Running benchmarks...
$(GO) test -bench=. \
$(BENCH_FLAGS) \
-run=^$ \
-benchtime=$(BENCH_TIME) \
./...
.PHONY: lint
lint: ## Run linters
$(INFO) Running linters...
$(GOLANGCI_LINT) run --fix
$(SUCCESS) Lint complete!
.PHONY: fmt
fmt: ## Format code
$(INFO) Formatting code...
$(GO) fmt ./...
$(GOFUMPT) -l -w .
$(SUCCESS) Format complete!
.PHONY: vet
vet: ## Run go vet
$(INFO) Running go vet...
$(GO) vet ./...
$(SUCCESS) Vet complete!
.PHONY: security
security: ## Run security checks
$(INFO) Running security checks...
$(GOVULNCHECK) ./...
$(SUCCESS) Security check complete!
# =============================================================================
# πŸ—οΈ Build Variations
# =============================================================================
.PHONY: build-all
build-all: $(DIST_DIR) ## Build for all platforms
$(WORKING) Building for all platforms...
@$(foreach platform,$(PLATFORMS),\
$(eval OS := $(word 1,$(subst /, ,$(platform)))) \
$(eval ARCH := $(word 2,$(subst /, ,$(platform)))) \
$(eval ARM := $(word 3,$(subst /, ,$(platform)))) \
$(WORKING) Building for $(OS)/$(ARCH)$(if $(ARM),/v$(ARM))... && \
GOOS=$(OS) GOARCH=$(ARCH) $(if $(ARM),GOARM=$(ARM)) \
CGO_ENABLED=$(CGO_ENABLED) \
$(GO) build -tags '$(ALL_TAGS)' \
-ldflags '$(LD_FLAGS)' \
-o $(DIST_DIR)/$(PROJECT_NAME)-$(OS)-$(ARCH)$(if $(ARM),v$(ARM))$(if $(findstring windows,$(OS)),.exe,) \
./cmd/$(PROJECT_NAME) ; \
)
$(PACKAGE) Creating release archives...
@cd $(DIST_DIR) && \
for file in $(PROJECT_NAME)-* ; do \
if [ -f "$$file" ]; then \
tar czf "$$file.tar.gz" "$$file" || exit 1; \
rm -f "$$file"; \
fi \
done
$(SUCCESS) All platforms built and archived!
.PHONY: build-debug
build-debug: GCFLAGS += -N -l ## Build with debug symbols
build-debug: BUILD_TAGS += debug
build-debug: build
.PHONY: build-race
build-race: CGO_ENABLED=1 ## Build with race detector
build-race: BUILD_TAGS += race
build-race: build
# =============================================================================
# πŸ“¦ Docker Support
# =============================================================================
.PHONY: docker-build
docker-build: ## Build Docker image
$(WORKING) Building Docker image...
docker build $(DOCKER_BUILD_ARGS) \
--build-arg VERSION=$(VERSION) \
--build-arg BUILD_TIME=$(BUILD_TIME) \
--build-arg GIT_COMMIT=$(GIT_COMMIT) \
-f $(DOCKERFILE) \
-t $(DOCKER_IMAGE):$(DOCKER_TAG) \
$(DOCKER_BUILD_CONTEXT)
$(SUCCESS) Docker image built!
.PHONY: docker-push
docker-push: ## Push Docker image
$(WORKING) Pushing Docker image...
docker push $(DOCKER_IMAGE):$(DOCKER_TAG)
$(SUCCESS) Docker image pushed!
.PHONY: docker-run
docker-run: ## Run Docker container
$(ROCKET) Running Docker container...
docker run --rm -it $(DOCKER_IMAGE):$(DOCKER_TAG)
# =============================================================================
# πŸ—„οΈ Database Operations
# =============================================================================
.PHONY: db-migrate
db-migrate: ## Run database migrations
$(INFO) Running database migrations...
@if [ -d "$(MIGRATIONS_DIR)" ]; then \
go run -tags 'postgres mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest \
-database "$(DATABASE_URL)" \
-path $(MIGRATIONS_DIR) up; \
else \
$(WARN) No migrations directory found; \
fi
.PHONY: db-rollback
db-rollback: ## Rollback database migration
$(INFO) Rolling back database migration...
go run -tags 'postgres mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest \
-database "$(DATABASE_URL)" \
-path $(MIGRATIONS_DIR) down 1
.PHONY: db-reset
db-reset: ## Reset database
$(WARN) Resetting database...
go run -tags 'postgres mysql' github.com/golang-migrate/migrate/v4/cmd/migrate@latest \
-database "$(DATABASE_URL)" \
-path $(MIGRATIONS_DIR) drop -f
# =============================================================================
# πŸ“Š Reporting & Analytics
# =============================================================================
.PHONY: report
report: ## Generate project reports
$(INFO) Generating project reports...
@mkdir -p $(DOCS_DIR)/reports
@$(MAKE) test-coverage
@$(MAKE) benchmark-report
@$(MAKE) lint-report
@$(MAKE) security-report
$(SUCCESS) Reports generated in $(DOCS_DIR)/reports
.PHONY: benchmark-report
benchmark-report:
$(GO) test -bench=. -benchmem ./... > $(DOCS_DIR)/reports/benchmark.txt
.PHONY: lint-report
lint-report:
$(GOLANGCI_LINT) run --out-format checkstyle > $(DOCS_DIR)/reports/lint-checkstyle.xml
.PHONY: security-report
security-report:
$(GOVULNCHECK) -json ./... > $(DOCS_DIR)/reports/security.json
# =============================================================================
# πŸ”„ CI/CD Integration
# =============================================================================
.PHONY: ci
ci: ## Run CI pipeline
$(INFO) Running CI pipeline...
@$(MAKE) deps-verify
@$(MAKE) lint
@$(MAKE) test-coverage
@$(MAKE) security
@$(MAKE) build
$(SUCCESS) CI pipeline complete!
.PHONY: cd
cd: ## Run CD pipeline
$(INFO) Running CD pipeline...
@$(MAKE) build
@if [ "$(ENABLE_DOCKER)" = "true" ]; then \
$(MAKE) docker-build; \
$(MAKE) docker-push; \
fi
$(SUCCESS) CD pipeline complete!
# =============================================================================
# 🧹 Cleanup & Maintenance
# =============================================================================
.PHONY: clean
clean: ## Clean build artifacts
$(TRASH) Cleaning build artifacts...
rm -rf $(BIN_DIR) $(DIST_DIR)
$(GO) clean -cache -testcache -modcache
$(SUCCESS) Clean complete!
.PHONY: deps
deps: ## Install dependencies
$(WORKING) Installing dependencies...
$(GO) mod download
@if [ ! -f "$(GOLANGCI_LINT)" ]; then \
$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
fi
@if [ ! -f "$(GOFUMPT)" ]; then \
$(GO) install mvdan.cc/gofumpt@latest; \
fi
@if [ ! -f "$(GOVULNCHECK)" ]; then \
$(GO) install golang.org/x/vuln/cmd/govulncheck@latest; \
fi
@if [ ! -f "$(MOCKGEN)" ]; then \
$(GO) install github.com/golang/mock/mockgen@latest; \
fi
@if [ ! -f "$(AIR)" ]; then \
$(GO) install github.com/cosmtrek/air@latest; \
fi
$(SUCCESS) Dependencies installed!
.PHONY: deps-update
deps-update: ## Update dependencies
$(WORKING) Updating dependencies...
$(GO) get -u ./...
$(GO) mod tidy
$(SUCCESS) Dependencies updated!
.PHONY: deps-verify
deps-verify: ## Verify dependencies
$(INFO) Verifying dependencies...
$(GO) mod verify
$(SUCCESS) Dependencies verified!
# =============================================================================
# πŸ“š Documentation
# =============================================================================
.PHONY: docs
docs: $(DOCS_DIR) ## Generate documentation
$(WORKING) Generating documentation...
@mkdir -p $(DOCS_DIR)
$(GO) doc -all > $(DOCS_DIR)/API.md
@if [ -f "README.md.tmpl" ]; then \
VERSION=$(VERSION) \
BUILD_TIME=$(BUILD_TIME) \
envsubst < README.md.tmpl > README.md; \
fi
$(SUCCESS) Documentation generated!
.PHONY: serve-docs
serve-docs: ## Serve documentation locally
$(ROCKET) Serving documentation at http://localhost:6060
$(GODOC) -http=:6060
# =============================================================================
# πŸ› οΈ Tools & Utilities
# =============================================================================
.PHONY: tools
tools: ## Install all tools
$(INFO) Installing tools...
$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
$(GO) install mvdan.cc/gofumpt@latest
$(GO) install golang.org/x/vuln/cmd/govulncheck@latest
$(GO) install github.com/golang/mock/mockgen@latest
$(GO) install github.com/cosmtrek/air@latest
$(GO) install github.com/swaggo/swag/cmd/swag@latest
$(SUCCESS) Tools installed!
.PHONY: proto
proto: ## Generate protocol buffers
$(WORKING) Generating protocol buffers...
@if [ -d "$(PROTO_DIR)" ]; then \
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
$(PROTO_DIR)/*.proto; \
fi
$(SUCCESS) Protocol buffers generated!
.PHONY: mock
mock: ## Generate mocks
$(WORKING) Generating mocks...
$(MOCKGEN) -source=pkg/interfaces.go -destination=pkg/mocks/mocks.go
$(SUCCESS) Mocks generated!
.PHONY: version
version: ## Display version information
@echo "$(CYAN)Version:$(RESET) $(VERSION)"
@echo "$(CYAN)Commit:$(RESET) $(GIT_COMMIT)"
@echo "$(CYAN)Branch:$(RESET) $(GIT_BRANCH)"
@echo "$(CYAN)Built:$(RESET) $(BUILD_TIME)"
@echo "$(CYAN)Built by:$(RESET) $(BUILD_BY)"
@echo "$(CYAN)Go version:$(RESET) $(shell $(GO) version)"
# =============================================================================
# πŸ“ Directory Creation
# =============================================================================
$(BIN_DIR) $(DIST_DIR) $(DOCS_DIR):
mkdir -p $@
# =============================================================================
# πŸ’‘ Help
# =============================================================================
.PHONY: help
help: ## Show this help message
@echo "$(CYAN)$(BOLD)$(PROJECT_NAME) - $(DESCRIPTION)$(RESET)"
@echo "$(WHITE)Maintained by $(MAINTAINER)$(RESET)\n"
@echo "$(CYAN)$(BOLD)Available targets:$(RESET)"
@awk 'BEGIN {FS = ":.*##"; printf ""} \
/^[a-zA-Z_-]+:.*?##/ { printf " $(CYAN)%-20s$(RESET) %s\n", $$1, $$2 } \
/^##@/ { printf "\n$(MAGENTA)%s$(RESET)\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment