name: V2 CI/CD Pipeline on: push: branches: - 'feature/v2-**' - 'feature/v2/**' pull_request: branches: - 'feature/v2-prep' - 'master' paths: - 'pkg/**' - 'cmd/**' - 'internal/**' - 'go.mod' - 'go.sum' - '.github/workflows/**' workflow_dispatch: inputs: run_benchmarks: description: 'Run performance benchmarks' required: false default: 'true' type: boolean env: GO_VERSION: '1.25' MIN_COVERAGE: 100 GOLANGCI_LINT_VERSION: 'v1.61.0' jobs: # ============================================================================== # PRE-FLIGHT CHECKS # ============================================================================== pre_flight: name: Pre-Flight Checks runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Validate branch naming run: | BRANCH_NAME="${{ github.head_ref || github.ref_name }}" if [[ "${{ github.event_name }}" == "pull_request" ]]; then if [[ ! "$BRANCH_NAME" =~ ^feature/v2/[a-z0-9-]+/[A-Z0-9]+-[0-9]+-[a-z0-9-]+$ ]]; then echo "❌ Invalid branch name: $BRANCH_NAME" echo "" echo "Branch must follow: feature/v2//-" echo "" echo "Examples:" echo " feature/v2/parsers/P2-002-uniswap-v2-base" echo " feature/v2/cache/P3-001-address-index" echo " feature/v2/validation/P4-001-validation-rules" exit 1 fi fi echo "✅ Branch naming validation passed" - name: Check commit message format if: github.event_name == 'push' run: | # Get the last commit message COMMIT_MSG=$(git log -1 --pretty=%B) # Check format: type(scope): description if [[ ! "$COMMIT_MSG" =~ ^(feat|fix|perf|refactor|test|docs|build|ci)\([a-z0-9-]+\):\ .+ ]]; then echo "❌ Invalid commit message format" echo "" echo "Format: type(scope): brief description" echo "" echo "Types: feat, fix, perf, refactor, test, docs, build, ci" echo "" echo "Example:" echo " feat(parsers): add UniswapV2 parser with event validation" exit 1 fi echo "✅ Commit message format valid" # ============================================================================== # BUILD & DEPENDENCIES # ============================================================================== build: name: Build & Dependencies runs-on: ubuntu-latest needs: pre_flight steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go ${{ env.GO_VERSION }} uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} cache: true - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go-${{ env.GO_VERSION }}- - name: Download dependencies run: go mod download - name: Verify dependencies run: go mod verify - name: Check for tidy modules run: | go mod tidy if [ -n "$(git status --porcelain go.mod go.sum)" ]; then echo "❌ go.mod or go.sum is not tidy" echo "Run: go mod tidy" git diff go.mod go.sum exit 1 fi echo "✅ Dependencies are tidy" - name: Build all packages run: go build -v ./... - name: Build main binary (if exists) run: | if [ -d "cmd/mev-bot" ]; then go build -v -o bin/mev-bot ./cmd/mev-bot echo "✅ Binary built successfully" else echo "ℹ️ No main application yet (planning phase)" fi # ============================================================================== # CODE QUALITY # ============================================================================== code_quality: name: Code Quality & Linting runs-on: ubuntu-latest needs: build steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run gofmt run: | if [ -n "$(gofmt -l .)" ]; then echo "❌ Code is not formatted" echo "Files needing formatting:" gofmt -l . echo "" echo "Run: gofmt -w ." exit 1 fi echo "✅ Code formatting passed" - name: Run go vet run: go vet ./... - name: Run golangci-lint uses: golangci/golangci-lint-action@v6 with: version: ${{ env.GOLANGCI_LINT_VERSION }} args: --timeout=10m --config=.golangci.yml - name: Run gosec security scanner run: | go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest gosec -fmt sarif -out gosec.sarif ./... || true - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: gosec.sarif - name: Check for TODO/FIXME comments run: | if grep -r "TODO\|FIXME" --include="*.go" pkg/ cmd/ internal/ | grep -v "_test.go"; then echo "⚠️ TODO/FIXME comments found - ensure they're tracked in issues" fi # ============================================================================== # UNIT TESTS WITH 100% COVERAGE ENFORCEMENT # ============================================================================== unit_tests: name: Unit Tests (100% Coverage Required) runs-on: ubuntu-latest needs: build steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - name: Run tests with race detector run: | go test -v -race -timeout=30m ./... - name: Generate coverage report run: | go test -v -race -coverprofile=coverage.out -covermode=atomic ./... - name: Calculate coverage percentage id: coverage run: | COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT echo "Coverage: $COVERAGE%" - name: Enforce 100% coverage requirement run: | COVERAGE=${{ steps.coverage.outputs.coverage }} MIN_COVERAGE=${{ env.MIN_COVERAGE }} echo "Coverage: $COVERAGE%" echo "Minimum Required: $MIN_COVERAGE%" # Use bc for floating point comparison if (( $(echo "$COVERAGE < $MIN_COVERAGE" | bc -l) )); then echo "" echo "❌ COVERAGE FAILURE" echo "Coverage $COVERAGE% is below required $MIN_COVERAGE%" echo "" echo "Uncovered lines:" go tool cover -func=coverage.out | grep -v "100.0%" echo "" echo "See docs/planning/03_TESTING_REQUIREMENTS.md for details" exit 1 fi echo "✅ Coverage requirement met: $COVERAGE%" - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: file: ./coverage.out flags: unittests name: v2-coverage - name: Generate HTML coverage report run: | go tool cover -html=coverage.out -o coverage.html - name: Upload coverage artifacts uses: actions/upload-artifact@v4 with: name: coverage-report path: | coverage.out coverage.html retention-days: 30 # ============================================================================== # INTEGRATION TESTS # ============================================================================== integration_tests: name: Integration Tests runs-on: ubuntu-latest needs: unit_tests if: contains(github.event.head_commit.message, '[integration]') || github.event_name == 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Cache Go modules uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/go/pkg/mod key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} - name: Run integration tests run: | go test -v -timeout=30m -tags=integration ./... - name: Run end-to-end tests run: | if [ -d "tests/e2e" ]; then go test -v -timeout=30m ./tests/e2e/... fi # ============================================================================== # PERFORMANCE BENCHMARKS # ============================================================================== benchmarks: name: Performance Benchmarks runs-on: ubuntu-latest needs: unit_tests if: github.event.inputs.run_benchmarks == 'true' || contains(github.event.head_commit.message, '[bench]') steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run benchmarks run: | go test -bench=. -benchmem -benchtime=10s ./... > benchmark.txt cat benchmark.txt - name: Check performance thresholds run: | echo "Checking parser performance targets..." # Parser should be < 5ms per transaction # Arbitrage detection should be < 10ms # End-to-end should be < 50ms echo "✅ Performance benchmarks completed" echo "Review benchmark.txt for detailed results" - name: Upload benchmark results uses: actions/upload-artifact@v4 with: name: benchmarks path: benchmark.txt retention-days: 90 # ============================================================================== # DECIMAL PRECISION TESTS # ============================================================================== decimal_tests: name: Decimal Precision Validation runs-on: ubuntu-latest needs: unit_tests steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run decimal precision tests run: | # Run tests that specifically test decimal handling go test -v -run TestDecimal ./... echo "✅ Decimal precision tests passed" # ============================================================================== # MODULARITY VALIDATION # ============================================================================== modularity_check: name: Modularity Validation runs-on: ubuntu-latest needs: build steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Check component independence run: | echo "Validating component modularity..." # Each pkg/* should compile independently for dir in pkg/*/; do if [ -d "$dir" ]; then echo "Testing $dir..." (cd "$dir" && go build .) || exit 1 fi done echo "✅ All components compile independently" - name: Check for circular dependencies run: | go install golang.org/x/tools/cmd/godepgraph@latest godepgraph ./... | grep -i cycle && exit 1 || echo "✅ No circular dependencies" # ============================================================================== # FINAL VALIDATION # ============================================================================== final_check: name: Final Validation Summary runs-on: ubuntu-latest needs: - pre_flight - build - code_quality - unit_tests - modularity_check - decimal_tests if: always() steps: - name: Check all jobs status run: | echo "# 🤖 MEV Bot V2 CI/CD Summary" > summary.md echo "" >> summary.md echo "**Commit**: ${{ github.sha }}" >> summary.md echo "**Branch**: ${{ github.ref_name }}" >> summary.md echo "**Timestamp**: $(date -u)" >> summary.md echo "" >> summary.md echo "## Test Results" >> summary.md echo "| Check | Status |" >> summary.md echo "|-------|--------|" >> summary.md echo "| Pre-Flight | ${{ needs.pre_flight.result == 'success' && '✅' || '❌' }} |" >> summary.md echo "| Build | ${{ needs.build.result == 'success' && '✅' || '❌' }} |" >> summary.md echo "| Code Quality | ${{ needs.code_quality.result == 'success' && '✅' || '❌' }} |" >> summary.md echo "| Unit Tests (100% Coverage) | ${{ needs.unit_tests.result == 'success' && '✅' || '❌' }} |" >> summary.md echo "| Modularity | ${{ needs.modularity_check.result == 'success' && '✅' || '❌' }} |" >> summary.md echo "| Decimal Precision | ${{ needs.decimal_tests.result == 'success' && '✅' || '❌' }} |" >> summary.md cat summary.md # Check if all required jobs passed if [[ "${{ needs.pre_flight.result }}" == "success" && "${{ needs.build.result }}" == "success" && "${{ needs.code_quality.result }}" == "success" && "${{ needs.unit_tests.result }}" == "success" && "${{ needs.modularity_check.result }}" == "success" && "${{ needs.decimal_tests.result }}" == "success" ]]; then echo "" >> summary.md echo "## ✅ ALL CHECKS PASSED" >> summary.md echo "Ready for merge to v2-prep branch" >> summary.md exit 0 else echo "" >> summary.md echo "## ❌ CHECKS FAILED" >> summary.md echo "Fix failing checks before merging" >> summary.md exit 1 fi - name: Upload summary uses: actions/upload-artifact@v4 if: always() with: name: ci-summary path: summary.md - name: Comment on PR uses: actions/github-script@v7 if: github.event_name == 'pull_request' && always() with: script: | const fs = require('fs'); const summary = fs.readFileSync('summary.md', 'utf8'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: summary });