diff --git a/.github/.env.base b/.github/.env.base index 21c5941..22178c7 100644 --- a/.github/.env.base +++ b/.github/.env.base @@ -235,7 +235,7 @@ REDIS_CACHE_FORCE_PULL=false # Force pull Redis images even when cache # 🪄 MAGE-X CONFIGURATION # ================================================================================================ -MAGE_X_VERSION=v1.13.0 # https://github.com/mrz1836/mage-x/releases +MAGE_X_VERSION=v1.15.0 # https://github.com/mrz1836/mage-x/releases MAGE_X_USE_LOCAL=false # Use local version for development MAGE_X_CI_SKIP_STEP_SUMMARY=true # Skip duplicate test results in step summary (already in test validation summary) MAGE_X_AUTO_DISCOVER_BUILD_TAGS=true # Enable auto-discovery of build tags @@ -244,7 +244,7 @@ MAGE_X_FORMAT_EXCLUDE_PATHS=vendor,node_modules,.git,.idea # Format exclusion MAGE_X_GITLEAKS_VERSION=8.30.0 # https://github.com/gitleaks/gitleaks/releases MAGE_X_GOFUMPT_VERSION=v0.9.2 # https://github.com/mvdan/gofumpt/releases MAGE_X_GOLANGCI_LINT_VERSION=v2.7.2 # https://github.com/golangci/golangci-lint/releases -MAGE_X_GORELEASER_VERSION=v2.13.1 # https://github.com/goreleaser/goreleaser/releases +MAGE_X_GORELEASER_VERSION=v2.13.2 # https://github.com/goreleaser/goreleaser/releases MAGE_X_GOVULNCHECK_VERSION=v1.1.4 # https://go.googlesource.com/vuln/+refs MAGE_X_GO_SECONDARY_VERSION=1.24.x # Secondary Go version for MAGE-X (also our secondary) MAGE_X_GO_VERSION=1.24.x # Primary Go version for MAGE-X (also our primary) @@ -252,7 +252,8 @@ MAGE_X_MOCKGEN_VERSION=v0.6.0 # https://github.c MAGE_X_NANCY_VERSION=v1.0.52 # https://github.com/sonatype-nexus-community/nancy/releases MAGE_X_STATICCHECK_VERSION=2025.1.1 # https://github.com/dominikh/go-tools/releases MAGE_X_SWAG_VERSION=v1.16.6 # https://github.com/swaggo/swag/releases -MAGE_X_YAMLFMT_VERSION=v0.20.0 # https://github.com/google/yamlfmt/releases +MAGE_X_YAMLFMT_VERSION=v0.21.0 # https://github.com/google/yamlfmt/releases +MAGE_X_BENCHSTAT_VERSION=v0.0.0-20251208221838-04cf7a2dca90 # https://pkg.go.dev/golang.org/x/perf/cmd/benchstat # Exclude magefiles from prebuild - they require 'mage' build tag and fail without it # MAGE_X_BUILD_EXCLUDE_PATTERN=magefiles diff --git a/.github/actions/setup-benchstat/action.yml b/.github/actions/setup-benchstat/action.yml new file mode 100644 index 0000000..4fc719b --- /dev/null +++ b/.github/actions/setup-benchstat/action.yml @@ -0,0 +1,168 @@ +# ------------------------------------------------------------------------------------ +# Setup Benchstat Composite Action (GoFortress) +# +# Purpose: Install and cache the benchstat binary for use in GitHub Actions workflows. +# Provides efficient caching by OS and version, with automatic binary installation +# on cache miss and PATH management for seamless integration. +# +# Features: +# - Smart binary caching by OS and version +# - Automatic go install only on cache miss +# - PATH management for immediate availability +# - Performance tracking outputs +# +# Usage: +# - uses: ./.github/actions/setup-benchstat +# with: +# benchstat-version: ${{ env.MAGE_X_BENCHSTAT_VERSION }} +# runner-os: ${{ runner.os }} +# go-version: ${{ matrix.go-version }} +# +# Maintainer: @mrz1836 +# +# ------------------------------------------------------------------------------------ + +name: "Setup Benchstat" +description: "Install and cache benchstat binary for benchmark comparison" + +inputs: + benchstat-version: + description: "Benchstat version to install (e.g., v0.6.0)" + required: true + runner-os: + description: "Runner OS for cache key (e.g., ubuntu-latest, mac-latest)" + required: true + go-version: + description: "Go version being used (e.g., 1.24.x, 1.22). Benchstat requires Go 1.23+" + required: true + +outputs: + cache-hit: + description: "Whether benchstat was restored from cache (true/false). Empty if skipped due to Go version." + value: ${{ steps.benchstat-cache.outputs.cache-hit }} + installation-method: + description: "How benchstat was obtained: cached, fresh, or skipped" + value: ${{ steps.installation-summary.outputs.method }} + skipped: + description: "Whether benchstat installation was skipped due to Go version < 1.23" + value: ${{ steps.version-check.outputs.skip }} + +runs: + using: "composite" + steps: + # -------------------------------------------------------------------- + # Check Go version compatibility (benchstat requires Go 1.23+) + # -------------------------------------------------------------------- + - name: 🔍 Check Go version compatibility + id: version-check + shell: bash + run: | + GO_VERSION="${{ inputs.go-version }}" + # Extract major and minor version: + # "1.24.x" -> MAJOR=1, MINOR=24 + # "1.22" -> MAJOR=1, MINOR=22 + # "1.23.5" -> MAJOR=1, MINOR=23 + # "2.0.0" -> MAJOR=2, MINOR=0 + MAJOR=$(echo "$GO_VERSION" | sed -E 's/^([0-9]+)\..*/\1/') + MINOR=$(echo "$GO_VERSION" | sed -E 's/^[0-9]+\.([0-9]+).*/\1/') + + if [ -z "$MAJOR" ] || [ -z "$MINOR" ] || ! [[ "$MAJOR" =~ ^[0-9]+$ ]] || ! [[ "$MINOR" =~ ^[0-9]+$ ]]; then + echo "❌ Could not parse Go version '$GO_VERSION'. Please provide a valid Go version (e.g., '1.23', '1.24.x')." >&2 + exit 1 + elif [ "$MAJOR" -gt 1 ]; then + # Any Go major version > 1 is considered compatible with the 1.23+ requirement + echo "✅ Go $GO_VERSION >= 1.23: proceeding with benchstat installation" + echo "skip=false" >> $GITHUB_OUTPUT + elif [ "$MAJOR" -eq 1 ] && [ "$MINOR" -lt 23 ]; then + echo "⚠️ Go $GO_VERSION < 1.23: skipping benchstat installation (requires Go 1.23+)" + echo "skip=true" >> $GITHUB_OUTPUT + else + echo "✅ Go $GO_VERSION >= 1.23: proceeding with benchstat installation" + echo "skip=false" >> $GITHUB_OUTPUT + fi + + # -------------------------------------------------------------------- + # Restore benchstat binary cache + # -------------------------------------------------------------------- + - name: 💾 Restore benchstat binary cache + if: steps.version-check.outputs.skip != 'true' + id: benchstat-cache + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: ~/.cache/benchstat-bin + key: ${{ inputs.runner-os }}-benchstat-${{ inputs.benchstat-version }} + + # -------------------------------------------------------------------- + # Install cached binary to PATH when cache hits + # -------------------------------------------------------------------- + - name: 📦 Install cached benchstat to PATH + if: steps.version-check.outputs.skip != 'true' && steps.benchstat-cache.outputs.cache-hit == 'true' + shell: bash + run: | + echo "📦 Installing cached benchstat binary to PATH..." + + # Copy cached binary to GOPATH and add to PATH + mkdir -p "$(go env GOPATH)/bin" + cp ~/.cache/benchstat-bin/benchstat "$(go env GOPATH)/bin/benchstat" + chmod +x "$(go env GOPATH)/bin/benchstat" + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + + echo "✅ Cached benchstat binary installed to PATH" + + # -------------------------------------------------------------------- + # Install benchstat via go install when cache misses + # -------------------------------------------------------------------- + - name: ⬇️ Install benchstat (cache miss) + if: steps.version-check.outputs.skip != 'true' && steps.benchstat-cache.outputs.cache-hit != 'true' + shell: bash + run: | + echo "⬇️ Cache miss – installing benchstat via go install..." + echo "📋 Installing benchstat version: ${{ inputs.benchstat-version }}" + + # Install benchstat + go install "golang.org/x/perf/cmd/benchstat@${{ inputs.benchstat-version }}" + + # Cache the binary for future runs + mkdir -p ~/.cache/benchstat-bin + cp "$(go env GOPATH)/bin/benchstat" ~/.cache/benchstat-bin/benchstat + + # Ensure GOPATH/bin is in PATH + echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" + + echo "✅ Benchstat installed and cached" + + # -------------------------------------------------------------------- + # Verify benchstat installation and set outputs + # -------------------------------------------------------------------- + - name: 🔍 Verify benchstat installation + id: installation-summary + shell: bash + run: | + # Check if installation was skipped due to Go version + if [[ "${{ steps.version-check.outputs.skip }}" == "true" ]]; then + echo "⏭️ Benchstat installation skipped (Go version < 1.23)" + echo "method=skipped" >> $GITHUB_OUTPUT + echo "📋 Installation method: Skipped" + exit 0 + fi + + echo "🔍 Verifying benchstat installation..." + + # Test that benchstat is available and working + if ! command -v benchstat >/dev/null 2>&1; then + echo "❌ ERROR: benchstat is not available in PATH" >&2 + exit 1 + fi + + # Show version + echo "✅ benchstat is available" + benchstat -h 2>&1 | head -3 || true + + # Determine installation method + if [[ "${{ steps.benchstat-cache.outputs.cache-hit }}" == "true" ]]; then + echo "method=cached" >> $GITHUB_OUTPUT + echo "📋 Installation method: Cached" + else + echo "method=fresh" >> $GITHUB_OUTPUT + echo "📋 Installation method: Fresh install" + fi diff --git a/.github/actions/upload-statistics/action.yml b/.github/actions/upload-statistics/action.yml index b0ff4d8..145f1ad 100644 --- a/.github/actions/upload-statistics/action.yml +++ b/.github/actions/upload-statistics/action.yml @@ -45,6 +45,10 @@ inputs: description: "Compression level for the artifact (0-9, 6 is default)" required: false default: "6" + continue-on-error: + description: "Continue workflow if upload fails (for non-critical artifacts)" + required: false + default: "false" runs: using: "composite" @@ -54,6 +58,7 @@ runs: # -------------------------------------------------------------------- - name: 📤 Upload ${{ inputs.artifact-name }} if: always() # Always run to capture data even on job failure + continue-on-error: ${{ inputs.continue-on-error == 'true' }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ${{ inputs.artifact-name }} diff --git a/.github/tech-conventions/README.md b/.github/tech-conventions/README.md index eb8498f..a220d2f 100644 --- a/.github/tech-conventions/README.md +++ b/.github/tech-conventions/README.md @@ -59,5 +59,5 @@ Creating and maintaining GitHub Actions workflows with security, reliability, an ### 🏗️ Build & Project Setup -**[MAGE-X Build Automation](mage-x.md)** -Zero-boilerplate build automation system with 150+ built-in commands that replaces Makefiles. Includes installation, configuration, command reference, and migration guide. +**[MAGE-X Build Tooling](mage-x.md)** +Zero-boilerplate build toolchain with 150+ built-in commands that replaces Makefiles. Includes installation, configuration, command reference, and migration guide. diff --git a/.github/tech-conventions/mage-x.md b/.github/tech-conventions/mage-x.md index 3fc200f..78d8507 100644 --- a/.github/tech-conventions/mage-x.md +++ b/.github/tech-conventions/mage-x.md @@ -1,16 +1,16 @@ -# MAGE-X Build Automation +# MAGE-X Build Tooling -> Zero-boilerplate build automation for Go projects that replaces Makefiles with 150+ built-in commands and intelligent configuration. +> Zero-boilerplate build tooling for Go projects that replaces Makefiles with 150+ built-in commands and intelligent configuration.

## 🚀 What is MAGE-X? -**MAGE-X** is a revolutionary zero-configuration build automation system for Go that provides **truly zero-boilerplate** development workflows. Unlike traditional build systems that require extensive configuration or wrapper functions, MAGE-X delivers all commands instantly through a single `magex` binary. +**MAGE-X** is a revolutionary zero-configuration build toolchain for Go that provides **truly zero-boilerplate** development workflows. Unlike traditional build systems that require extensive configuration or wrapper functions, MAGE-X delivers all commands instantly through a single `magex` binary. ### Core Philosophy -**"Write Once, Mage Everywhere: Production Build Automation for Go"** +**"Write Once, Mage Everywhere: Production Build Tooling for Go"** - **Zero Setup Required**: No magefile.go needed for basic operations - **150+ Built-in Commands**: Complete build, test, lint, release, and deployment workflows @@ -654,6 +654,6 @@ magex --help # Global help and options and list all comma 5. **Performance**: Significantly faster than traditional build tools 6. **Production Ready**: Security, compliance, and governance features built-in -MAGE-X transforms Go build automation from a chore into a productivity multiplier, enabling teams to focus on code rather than tooling configuration. +MAGE-X transforms Go build tasks from a chore into a productivity multiplier, enabling teams to focus on code rather than tooling configuration. -**Next Steps**: Install MAGE-X, run `magex build` in your project, and experience zero-configuration build automation. +**Next Steps**: Install MAGE-X, run `magex build` in your project, and experience zero-configuration build tooling. diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index b8f6246..6cea005 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -164,7 +164,7 @@ jobs: # -------------------------------------------------------------------- - name: 📊 Fetch Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b # v2.4.0 + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/fortress-completion-statistics.yml b/.github/workflows/fortress-completion-statistics.yml index ec943c4..13d8c5d 100644 --- a/.github/workflows/fortress-completion-statistics.yml +++ b/.github/workflows/fortress-completion-statistics.yml @@ -632,6 +632,7 @@ jobs: artifact-path: "statistics-section.md" retention-days: "1" if-no-files-found: "warn" + continue-on-error: "true" - name: 📋 Set Output Content id: set-output diff --git a/.github/workflows/fortress-coverage.yml b/.github/workflows/fortress-coverage.yml index 890191f..7f58cd5 100644 --- a/.github/workflows/fortress-coverage.yml +++ b/.github/workflows/fortress-coverage.yml @@ -737,7 +737,7 @@ jobs: # Count processed files from coverage output if [ -f "$COVERAGE_FILE" ]; then - FILES_PROCESSED=$(wc -l < "$COVERAGE_FILE" || echo "0") + FILES_PROCESSED=$(grep -v '^mode:' "$COVERAGE_FILE" | grep '^[^:]*:' | grep -o '^[^:]*' | sort -u | wc -l | tr -d ' ' || echo "0") echo "📁 Files processed: $FILES_PROCESSED" fi @@ -2425,12 +2425,51 @@ jobs: # Calculate coverage from coverage.txt file using go tool cover if [ -f "coverage-artifacts/coverage-data/coverage.txt" ]; then - COVERAGE_PERCENTAGE=$(go tool cover -func="coverage-artifacts/coverage-data/coverage.txt" | tail -1 | awk '{print $3}' | sed 's/%//' || echo "0") - FILES_PROCESSED=$(wc -l < "coverage-artifacts/coverage-data/coverage.txt" || echo "0") + # First, try direct calculation (suppress stderr to avoid module warnings) + COVERAGE_PERCENTAGE=$(go tool cover -func="coverage-artifacts/coverage-data/coverage.txt" 2>/dev/null | tail -1 | awk '{print $3}' | sed 's/%//' || true) + + # Validate result - must be a number (handles empty output or errors) + if [[ -z "$COVERAGE_PERCENTAGE" ]] || ! [[ "$COVERAGE_PERCENTAGE" =~ ^[0-9]+\.?[0-9]*$ ]]; then + echo "⚠️ Could not calculate coverage percentage directly, trying manual calculation..." + COVERAGE_PERCENTAGE="" + + # Fallback: Calculate from coverage file lines manually + # Coverage file format: path/file.go:startLine.startCol,endLine.endCol stmtCount hitCount + TOTAL_STATEMENTS=0 + COVERED_STATEMENTS=0 + while IFS= read -r line; do + # Skip header line (mode: ...) + [[ "$line" == mode:* ]] && continue + # Skip empty lines + [[ -z "$line" ]] && continue + # Extract statement count (first number) and hit count (second number) + # Format: path/file.go:startLine.startCol,endLine.endCol stmtCount hitCount + if [[ "$line" =~ [[:space:]]([0-9]+)[[:space:]]([0-9]+)$ ]]; then + STMT_COUNT="${BASH_REMATCH[1]}" + HIT_COUNT="${BASH_REMATCH[2]}" + TOTAL_STATEMENTS=$((TOTAL_STATEMENTS + STMT_COUNT)) + if [[ $HIT_COUNT -gt 0 ]]; then + COVERED_STATEMENTS=$((COVERED_STATEMENTS + STMT_COUNT)) + fi + fi + done < "coverage-artifacts/coverage-data/coverage.txt" + + if [[ $TOTAL_STATEMENTS -gt 0 ]]; then + COVERAGE_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($COVERED_STATEMENTS / $TOTAL_STATEMENTS) * 100}") + echo "📈 Calculated coverage manually: ${COVERAGE_PERCENTAGE}% ($COVERED_STATEMENTS/$TOTAL_STATEMENTS statements)" + else + COVERAGE_PERCENTAGE="0" + echo "⚠️ No coverage data found, defaulting to 0%" + fi + fi + + FILES_PROCESSED=$(grep -v '^mode:' "coverage-artifacts/coverage-data/coverage.txt" | grep '^[^:]*:' | grep -o '^[^:]*' | sort -u | wc -l | tr -d ' ' || echo "0") echo "📈 Calculated coverage percentage: ${COVERAGE_PERCENTAGE}%" echo "📁 Files processed: $FILES_PROCESSED" else echo "⚠️ Coverage file not found for statistics" + COVERAGE_PERCENTAGE="0" + FILES_PROCESSED="0" fi # Codecov job doesn't generate badges or deploy pages directly diff --git a/.github/workflows/fortress-test-matrix.yml b/.github/workflows/fortress-test-matrix.yml index a3acdc6..5cbc5eb 100644 --- a/.github/workflows/fortress-test-matrix.yml +++ b/.github/workflows/fortress-test-matrix.yml @@ -170,6 +170,17 @@ jobs: runner-os: ${{ matrix.os }} use-local: ${{ env.MAGE_X_USE_LOCAL }} + # -------------------------------------------------------------------- + # Setup benchstat (required for benchmark comparison tests) + # Note: benchstat requires Go 1.23+, action will skip for older versions + # -------------------------------------------------------------------- + - name: 📊 Setup benchstat + uses: ./.github/actions/setup-benchstat + with: + benchstat-version: ${{ env.MAGE_X_BENCHSTAT_VERSION }} + runner-os: ${{ matrix.os }} + go-version: ${{ matrix.go-version }} + # -------------------------------------------------------------------- # Setup Redis service using composite action with caching # -------------------------------------------------------------------- diff --git a/.gitpod.yml b/.gitpod.yml index c1942ee..00e4e6b 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,5 @@ -# Gitpod workspace configuration for go-wire -# Uses magex for build automation and development tasks +# Gitpod workspace configuration for this project. +# Uses magex for build tooling, linting, and testing. # This creates a one-click development environment for contributors image: gitpod/workspace-go:latest @@ -7,35 +7,35 @@ image: gitpod/workspace-go:latest tasks: - name: setup-and-test init: | - echo "🚀 Setting up go-wire development environment..." + echo "🚀 Setting up development environment..." echo "📦 Installing MAGE-X build tool..." go install github.com/mrz1836/mage-x/cmd/magex@latest - echo "📥 Downloading dependencies..." + echo "🔽 Downloading dependencies..." magex deps:download - echo "🔧 Initial build..." - magex build + echo "🔍 Running linters..." + magex lint echo "✅ Running initial tests..." magex test command: | echo "===============================================" - echo "🎯 Welcome to go-wire development!" + echo "🎯 Welcome to development environment!" echo "===============================================" echo "" echo "🛠️ Available magex commands:" echo " magex test - Run all tests" echo " magex lint - Run linters" echo " magex format:fix - Format the code" - echo " magex build - Build the project" + echo " magex build - Build the project (binary)" echo " magex help - List all available commands" echo "" echo "📖 Quick start:" echo " 1. Try: magex test" echo " 2. Make your changes" - echo " 3. Run: magex format:fix && magex lint && magex test" + echo " 3. Run: magex format:fix && magex lint && magex test:race" echo " 4. Commit and push your changes" echo "" echo "💡 For more help: magex help"