Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/.env.base
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -244,15 +244,16 @@ 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)
MAGE_X_MOCKGEN_VERSION=v0.6.0 # https://github.com/uber-go/mock/releases
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
Expand Down
168 changes: 168 additions & 0 deletions .github/actions/setup-benchstat/action.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions .github/actions/upload-statistics/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 }}
Expand Down
4 changes: 2 additions & 2 deletions .github/tech-conventions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
12 changes: 6 additions & 6 deletions .github/tech-conventions/mage-x.md
Original file line number Diff line number Diff line change
@@ -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.

<br><br>

## 🚀 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
Expand Down Expand Up @@ -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.
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/fortress-completion-statistics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 42 additions & 3 deletions .github/workflows/fortress-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/fortress-test-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
# --------------------------------------------------------------------
Expand Down
Loading