diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d42377b..d94059c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,6 @@ on: env: IMAGE_NAME: quay.io/dminnear/patternizer GO_VERSION: '1.24' - GOLANGCI_LINT_VERSION: 'v2.1.6' jobs: lint-and-format: @@ -28,26 +27,8 @@ jobs: go-version: ${{ env.GO_VERSION }} cache-dependency-path: src/go.sum - - name: Run gofmt - run: | - if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then - echo "The following files are not formatted:" - gofmt -s -l . - exit 1 - fi - working-directory: ./src - - - name: Run go vet - run: go vet ./... - working-directory: ./src - - - name: Install golangci-lint - run: | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin ${{ env.GOLANGCI_LINT_VERSION }} - - - name: Run golangci-lint - run: $(go env GOPATH)/bin/golangci-lint run - working-directory: ./src + - name: Run linting checks + run: make lint build-and-test: runs-on: ubuntu-latest @@ -63,26 +44,16 @@ jobs: cache-dependency-path: src/go.sum - name: Build binary - run: go build -v -o patternizer . - working-directory: ./src + run: make build - name: Run unit tests - run: | - echo "Running unit tests for all packages..." - go test -v ./... - working-directory: ./src + run: make test-unit - name: Generate test coverage report - run: | - echo "Generating test coverage report..." - go test ./... -coverprofile=coverage.out - go tool cover -func=coverage.out - working-directory: ./src + run: make test-coverage - name: Run integration tests - run: ./test/integration_test.sh - env: - PATTERNIZER_BINARY: ./src/patternizer + run: make test-integration build-container: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 962018f..500474c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ src/patternizer +src/coverage.out diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e9a4ec4 --- /dev/null +++ b/Makefile @@ -0,0 +1,155 @@ +# Makefile for patternizer + +# Variables +BINARY_NAME := patternizer +GO_VERSION := 1.24 +GOLANGCI_LINT_VERSION := v2.1.6 +IMAGE_NAME := patternizer +LOCAL_TAG := local +SRC_DIR := src +CONTAINER_ENGINE := podman + +# Go-related variables +GO_CMD := go +GO_BUILD := $(GO_CMD) build +GO_TEST := $(GO_CMD) test +GO_CLEAN := $(GO_CMD) clean +GO_VET := $(GO_CMD) vet +GO_FMT := gofmt + +# Default target +.DEFAULT_GOAL := help + +# Help target +.PHONY: help +help: ## Show this help message + @echo "Available targets:" + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +# Build target +.PHONY: build +build: ## Build the patternizer binary + @echo "Building patternizer..." + cd $(SRC_DIR) && $(GO_BUILD) -v -o $(BINARY_NAME) . + @echo "Build complete: $(SRC_DIR)/$(BINARY_NAME)" + +# Clean target +.PHONY: clean +clean: ## Clean build artifacts + @echo "Cleaning build artifacts..." + cd $(SRC_DIR) && $(GO_CLEAN) + rm -f $(SRC_DIR)/$(BINARY_NAME) + rm -f $(SRC_DIR)/coverage.out + @echo "Clean complete" + +# Install dependencies +.PHONY: deps +deps: ## Download and install Go dependencies + @echo "Installing dependencies..." + cd $(SRC_DIR) && $(GO_CMD) mod download + cd $(SRC_DIR) && $(GO_CMD) mod tidy + @echo "Dependencies installed" + +# Unit tests +.PHONY: test-unit +test-unit: ## Run unit tests + @echo "Running unit tests..." + cd $(SRC_DIR) && $(GO_TEST) -v ./... + +# Test with coverage +.PHONY: test-coverage +test-coverage: ## Run unit tests with coverage report + @echo "Running unit tests with coverage..." + cd $(SRC_DIR) && $(GO_TEST) ./... -coverprofile=coverage.out + cd $(SRC_DIR) && $(GO_CMD) tool cover -func=coverage.out + +# Integration tests +.PHONY: test-integration +test-integration: build ## Run integration tests + @echo "Running integration tests..." + PATTERNIZER_BINARY=./$(SRC_DIR)/$(BINARY_NAME) ./test/integration_test.sh + +# All tests +.PHONY: test +test: test-unit test-integration ## Run all tests (unit + integration) + +# Lint target +.PHONY: lint +lint: lint-fmt lint-vet lint-golangci ## Run all linting checks + +# Format check +.PHONY: lint-fmt +lint-fmt: ## Check Go formatting + @echo "Checking Go formatting..." + @cd $(SRC_DIR) && if [ "$$($(GO_FMT) -s -l . | wc -l)" -gt 0 ]; then \ + echo "The following files are not formatted:"; \ + $(GO_FMT) -s -l .; \ + exit 1; \ + fi + @echo "Go formatting check passed" + +# Vet check +.PHONY: lint-vet +lint-vet: ## Run go vet + @echo "Running go vet..." + cd $(SRC_DIR) && $(GO_VET) ./... + @echo "Go vet passed" + +# golangci-lint check +.PHONY: lint-golangci +lint-golangci: ## Run golangci-lint + @echo "Running golangci-lint..." + @if ! command -v golangci-lint >/dev/null 2>&1; then \ + echo "Installing golangci-lint..."; \ + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $$(go env GOPATH)/bin $(GOLANGCI_LINT_VERSION); \ + fi + cd $(SRC_DIR) && $$(go env GOPATH)/bin/golangci-lint run + @echo "golangci-lint passed" + +# Format code +.PHONY: fmt +fmt: ## Format Go code + @echo "Formatting Go code..." + cd $(SRC_DIR) && $(GO_FMT) -s -w . + @echo "Go code formatted" + +# Local container build +.PHONY: local-container-build +local-container-build: ## Build container image locally + @echo "Building container image..." + $(CONTAINER_ENGINE) build -t $(IMAGE_NAME):$(LOCAL_TAG) -f Containerfile . + @echo "Container image built: $(IMAGE_NAME):$(LOCAL_TAG)" + +# Full CI pipeline locally +.PHONY: ci +ci: lint build test ## Run the full CI pipeline locally + +# Development setup +.PHONY: dev-setup +dev-setup: deps ## Set up development environment + @echo "Setting up development environment..." + @if ! command -v golangci-lint >/dev/null 2>&1; then \ + echo "Installing golangci-lint..."; \ + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $$(go env GOPATH)/bin $(GOLANGCI_LINT_VERSION); \ + fi + @echo "Development environment ready" + +# Version info +.PHONY: version +version: ## Show version information + @echo "Go version: $$(go version)" + @echo "Git commit: $$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')" + @echo "Build date: $$(date -u +%Y-%m-%dT%H:%M:%SZ)" + +# Generate documentation +.PHONY: docs +docs: ## Generate Go documentation + @echo "Generating documentation..." + cd $(SRC_DIR) && $(GO_CMD) doc -all ./... + +# Quick check (fast feedback loop) +.PHONY: check +check: lint-fmt lint-vet build test-unit ## Quick check (format, vet, build, unit tests) + +.PHONY: all +all: clean deps lint build test local-container-build ## Run everything diff --git a/README.md b/README.md index f6c152b..8941d9f 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,25 @@ The tool provides both a standalone CLI and containerized execution for maximum - 🔐 **Secrets integration** with Vault and External Secrets support - ✅ **Comprehensive testing** with unit and integration tests - 🏗️ **Multi-stage builds** for minimal container images +- 🛠️ **Makefile-driven development** for consistent local development and CI + +## Quick Start for Developers + +```bash +# Clone the repository +git clone https://github.com/dminnear-rh/patternizer.git +cd patternizer + +# Set up development environment +make dev-setup + +# See all available targets +make help + +# Build and test +make build +make test +``` --- @@ -103,34 +122,41 @@ podman run --rm -it -v .:/repo:z quay.io/dminnear/patternizer init --with-secret - Go 1.24+ - Podman or Docker - Git +- Make -### Building the CLI +### Quick Start ```bash -cd src -go build -o patternizer . +# Set up development environment (installs dependencies and tools) +make dev-setup + +# Show all available targets +make help ``` -### Running Tests +### Common Development Tasks ```bash -# Run unit tests -cd src -go test -v ./... +# Build the CLI +make build -# Run integration tests (requires built binary) -cd .. -./test/integration_test.sh -``` +# Run all tests (unit + integration) +make test -### Building the Container +# Run only unit tests +make test-unit -```bash -# Build with default settings -podman build -t patternizer:local . +# Run only integration tests +make test-integration + +# Build container image locally +make local-container-build -# Build with custom alpine version -podman build --build-arg ALPINE_VERSION=3.22 -t patternizer:local . +# Run full CI pipeline locally +make ci + +# Quick feedback loop (format check, vet, build, unit tests) +make check ``` ### Code Quality @@ -138,16 +164,16 @@ podman build --build-arg ALPINE_VERSION=3.22 -t patternizer:local . The project uses comprehensive linting and formatting: ```bash -cd src +# Run all linting checks (gofmt, go vet, golangci-lint) +make lint # Format code -gofmt -s -w . - -# Run linter -golangci-lint run +make fmt -# Run vet -go vet ./... +# Run individual lint checks +make lint-fmt # gofmt check +make lint-vet # go vet +make lint-golangci # golangci-lint ``` --- @@ -189,25 +215,27 @@ The integration test (`test/integration_test.sh`) validates the complete workflo Run integration tests locally: ```bash -# Build the binary first -cd src && go build -o patternizer . +# Run integration tests (automatically builds binary first) +make test-integration -# Run integration tests -cd .. && ./test/integration_test.sh +# Or run all tests (unit + integration) +make test ``` --- ## CI/CD Pipeline -The project uses a comprehensive CI pipeline with three stages: +The project uses a comprehensive CI pipeline with three stages that leverage the Makefile for consistency: -1. **Lint & Format**: Code quality checks with `gofmt`, `go vet`, and `golangci-lint` -2. **Build & Test**: Binary compilation, unit tests, and integration tests +1. **Lint & Format**: `make lint` - Code quality checks with `gofmt`, `go vet`, and `golangci-lint` +2. **Build & Test**: `make build`, `make test-unit`, `make test-coverage`, `make test-integration` 3. **Container Build**: Multi-stage container build and push to Quay.io All code must pass linting and tests before being merged or deployed. +The CI pipeline uses the same Makefile targets that developers use locally, ensuring perfect consistency between local development and CI environments. You can run the same checks locally with `make ci`. + --- ## Architecture @@ -243,7 +271,27 @@ This modular design makes the codebase maintainable, testable, and extensible. 1. Fork the repository 2. Create a feature branch 3. Make your changes -4. Run tests: `go test ./... && ./test/integration_test.sh` +4. Run the development workflow: + ```bash + make dev-setup # Set up development environment + make check # Quick feedback loop + make test # Run all tests + make lint # Run all linting checks + ``` 5. Submit a pull request All contributions must pass the CI pipeline including linting, formatting, and comprehensive testing. + +### Development Workflow + +For the best development experience: +```bash +# Initial setup +make dev-setup + +# During development (fast feedback) +make check + +# Before committing +make ci # Runs the full CI pipeline locally +```