# Comprehensive Code Coverage CI Pipeline for Foxhunt HFT System # Enterprise-grade coverage measurement with 95% targets name: Code Coverage on: push: branches: [ main, master, develop ] pull_request: branches: [ main, master, develop ] schedule: # Run coverage analysis daily at 3 AM UTC - cron: '0 3 * * *' env: CARGO_TERM_COLOR: always RUSTFLAGS: "-C instrument-coverage" LLVM_PROFILE_FILE: "foxhunt-%p-%m.profraw" jobs: # Primary coverage job using llvm-cov (recommended approach) coverage-llvm: name: Coverage Analysis (LLVM-based) runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: # Fetch full history for accurate coverage comparison fetch-depth: 0 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Cache Rust dependencies uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target/ key: ${{ runner.os }}-cargo-coverage-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-coverage- ${{ runner.os }}-cargo- - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ postgresql-client \ bc - name: Run comprehensive coverage analysis run: | # Clean previous coverage data find . -name "*.profraw" -delete # Run tests with coverage instrumentation cargo llvm-cov --workspace \ --all-features \ --fail-under 95 \ --lcov --output-path lcov.info \ --html --output-dir coverage_html \ --exclude examples \ --exclude benchmarks \ --timeout 300 - name: Generate coverage summary run: | # Extract overall coverage percentage COVERAGE_PERCENT=$(cargo llvm-cov --workspace --all-features --summary-only | grep -o '[0-9.]*%' | head -1 | tr -d '%') echo "COVERAGE_PERCENT=$COVERAGE_PERCENT" >> $GITHUB_ENV # Generate coverage badge if (( $(echo "$COVERAGE_PERCENT >= 95" | bc -l) )); then BADGE_COLOR="brightgreen" elif (( $(echo "$COVERAGE_PERCENT >= 90" | bc -l) )); then BADGE_COLOR="green" elif (( $(echo "$COVERAGE_PERCENT >= 80" | bc -l) )); then BADGE_COLOR="yellow" else BADGE_COLOR="red" fi echo "BADGE_COLOR=$BADGE_COLOR" >> $GITHUB_ENV # Create coverage summary for PR comments cat > coverage_summary.md << EOF ## 📊 Code Coverage Report **Overall Coverage**: $COVERAGE_PERCENT% **Target**: 95% **Status**: $(if (( $(echo "$COVERAGE_PERCENT >= 95" | bc -l) )); then echo "✅ PASS"; else echo "❌ FAIL"; fi) ![Coverage Badge](https://img.shields.io/badge/coverage-$COVERAGE_PERCENT%25-$BADGE_COLOR) ### Component Targets - Core Trading Logic: 95% - Risk Management: 90% - Market Data: 85% - ML Models: 80% - Integration Tests: 70% - E2E Tests: 50% [📈 View Detailed HTML Report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) EOF - name: Upload LCOV report uses: actions/upload-artifact@v4 with: name: lcov-report-llvm path: lcov.info retention-days: 30 - name: Upload HTML coverage report uses: actions/upload-artifact@v4 with: name: html-coverage-report-llvm path: coverage_html/ retention-days: 30 - name: Upload coverage summary uses: actions/upload-artifact@v4 with: name: coverage-summary path: coverage_summary.md retention-days: 7 - name: Comment PR with coverage if: github.event_name == 'pull_request' uses: actions/github-script@v7 with: script: | const fs = require('fs'); const summary = fs.readFileSync('coverage_summary.md', 'utf8'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: summary }); - name: Fail on insufficient coverage run: | if (( $(echo "$COVERAGE_PERCENT < 95" | bc -l) )); then echo "❌ Coverage $COVERAGE_PERCENT% is below the required 95% threshold" exit 1 else echo "✅ Coverage $COVERAGE_PERCENT% meets the required 95% threshold" fi # Fallback coverage job using tarpaulin (with PIC fixes) coverage-tarpaulin: name: Coverage Analysis (Tarpaulin Fallback) runs-on: ubuntu-latest continue-on-error: true # Don't fail the workflow if tarpaulin has issues steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install cargo-tarpaulin run: cargo install cargo-tarpaulin - name: Cache Rust dependencies uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target/ key: ${{ runner.os }}-cargo-tarpaulin-${{ hashFiles('**/Cargo.lock') }} - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ postgresql-client - name: Run tarpaulin coverage (with PIC fix) env: RUSTFLAGS: "-C relocation-model=pic -C link-dead-code -C debuginfo=2" CARGO_INCREMENTAL: 0 run: | cargo tarpaulin \ --workspace \ --all-features \ --timeout 300 \ --target-dir target/tarpaulin \ --out Html \ --out Xml \ --out Lcov \ --output-dir target/coverage-tarpaulin \ --skip-clean \ --engine Auto \ --verbose || echo "Tarpaulin completed with warnings" - name: Upload tarpaulin reports uses: actions/upload-artifact@v4 if: always() with: name: tarpaulin-coverage-reports path: target/coverage-tarpaulin/ retention-days: 7 # Component-specific coverage analysis coverage-components: name: Component Coverage Analysis runs-on: ubuntu-latest continue-on-error: true strategy: matrix: component: - name: "trading-engine" packages: "trading-engine" target: 95 - name: "market-data" packages: "market-data" target: 85 - name: "persistence" packages: "persistence" target: 85 - name: "ai-intelligence" packages: "ai-intelligence ml-core ml-models" target: 80 - name: "risk-management" packages: "portfolio-management" target: 90 - name: "infrastructure" packages: "security monitoring gpu-compute" target: 70 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Run component coverage run: | cargo llvm-cov \ --packages ${{ matrix.component.packages }} \ --all-features \ --fail-under ${{ matrix.component.target }} \ --lcov --output-path ${{ matrix.component.name }}.lcov \ --html --output-dir coverage_${{ matrix.component.name }} - name: Upload component coverage uses: actions/upload-artifact@v4 with: name: coverage-${{ matrix.component.name }} path: | ${{ matrix.component.name }}.lcov coverage_${{ matrix.component.name }}/ retention-days: 14 # Coverage trend analysis coverage-trends: name: Coverage Trend Analysis runs-on: ubuntu-latest needs: [coverage-llvm] if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' steps: - name: Checkout repository uses: actions/checkout@v4 - name: Download coverage report uses: actions/download-artifact@v4 with: name: lcov-report-llvm - name: Store coverage history run: | # Create coverage history directory mkdir -p .coverage-history # Extract coverage percentage COVERAGE=$(grep -o 'SF:.*' lcov.info | wc -l) LINES_FOUND=$(grep -o 'LF:.*' lcov.info | cut -d: -f2 | paste -sd+ | bc) LINES_HIT=$(grep -o 'LH:.*' lcov.info | cut -d: -f2 | paste -sd+ | bc) COVERAGE_PERCENT=$(echo "scale=2; $LINES_HIT * 100 / $LINES_FOUND" | bc) # Store in history file echo "$(date -Iseconds),$COVERAGE_PERCENT,${{ github.sha }}" >> .coverage-history/coverage.csv # Keep only last 100 entries tail -100 .coverage-history/coverage.csv > .coverage-history/coverage.csv.tmp mv .coverage-history/coverage.csv.tmp .coverage-history/coverage.csv - name: Commit coverage history run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add .coverage-history/ git diff --staged --quiet || git commit -m "Update coverage history [skip ci]" git push || echo "No changes to push"