Skip to content

📈 Benchmark

📈 Benchmark #307

Workflow file for this run

name: 📈 Benchmark
on:
workflow_dispatch:
inputs:
benchmark_types:
description: 'Benchmark types to run (comma-separated)'
required: false
default: 'lighthouse,bundle-size,source-analysis,build-time,dev-server,resource-usage'
type: string
frameworks:
description: 'Frameworks to test (comma-separated, blank for all)'
required: false
default: ''
type: string
executions:
description: 'Number of executions per benchmark (for averaging)'
required: false
default: '1'
type: string
timeout_minutes:
description: 'Job timeout in minutes'
required: false
default: '60'
type: string
commit_to_main:
description: 'Commit results to main branch (results branch will always be updated)'
required: false
default: false
type: boolean
schedule:
- cron: '30 4 * * *' # Daily at 04:30 UTC
env:
NODE_VERSION: '20'
PYTHON_VERSION: '3.11'
jobs:
benchmark:
name: Run Framework Benchmarks
runs-on: ubuntu-latest
timeout-minutes: ${{ fromJson(github.event.inputs.timeout_minutes || '60') }}
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: 🔧 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: 🐍 Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: 📦 Install System Dependencies
run: |
# Update package lists
sudo apt-get update
# Install Chrome dependencies for Lighthouse (with Ubuntu 24.04 compatibility)
sudo apt-get install -y \
wget \
gnupg \
ca-certificates \
fonts-liberation \
libatk-bridge2.0-0 \
libdrm2 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
xdg-utils \
libgbm1 \
libxss1
# Install audio library (try both old and new package names)
sudo apt-get install -y libasound2t64 || sudo apt-get install -y libasound2
- name: 🌐 Install Google Chrome
uses: browser-actions/setup-chrome@v1
with:
chrome-version: stable
id: setup-chrome
- name: 📋 Verify Chrome Installation
run: |
echo "Chrome path: ${{ steps.setup-chrome.outputs.chrome-path }}"
${{ steps.setup-chrome.outputs.chrome-path }} --version
which google-chrome || which chromium-browser || echo "Chrome executable not found in PATH"
- name: 🔧 Setup Project
run: |
echo "Installing root dependencies..."
npm ci
echo "Installing Python dependencies..."
pip install -r scripts/requirements.txt
echo "Setting up project with npm run setup..."
npm run setup
- name: 🏗️ Build All Framework Apps
run: npm run build
- name: 🚀 Start Development Server
run: |
echo "Starting development server..."
npm start &
# Wait for server to be ready with timeout
timeout=60
elapsed=0
while [ $elapsed -lt $timeout ]; do
if curl -sf http://localhost:3000/health > /dev/null 2>&1; then
echo "✅ Server is ready!"
break
fi
echo "⏳ Waiting for server... (${elapsed}s)"
sleep 2
elapsed=$((elapsed + 2))
done
if [ $elapsed -ge $timeout ]; then
echo "❌ Server failed to start within ${timeout}s"
echo "Checking server logs..."
jobs
exit 1
fi
timeout-minutes: 2
- name: 🔍 Verify Project Setup
continue-on-error: true
run: |
echo "Verifying project setup (skipping tests since server is running)..."
cd scripts && python verify/main.py --skip-test
echo "Testing server endpoints..."
# Test health endpoint
curl -f http://localhost:3000/health || {
echo "❌ Health endpoint failed"
exit 1
}
# Test a few framework endpoints
for framework in react vue svelte; do
echo "Testing $framework endpoint..."
curl -f "http://localhost:3000/$framework/?mock=true" > /dev/null || {
echo "⚠️ $framework endpoint failed, but continuing..."
}
done
echo "✅ Project verification complete"
- name: 🔧 Prepare Benchmark Environment
run: |
echo "PYTHONPATH=$PWD:$PWD/scripts" >> $GITHUB_ENV
# Set commit behavior based on event type or manual input
if [ "${{ github.event_name }}" = "schedule" ]; then
echo "COMMIT_TO_MAIN=false" >> $GITHUB_ENV
echo "⏰ Scheduled run - will skip main branch commit"
echo "SCHEDULED_RUN=true" >> $GITHUB_ENV
else
echo "COMMIT_TO_MAIN=${{ github.event.inputs.commit_to_main || 'false' }}" >> $GITHUB_ENV
echo "👤 Manual run - commit to main: ${{ github.event.inputs.commit_to_main || 'false' }}"
echo "SCHEDULED_RUN=false" >> $GITHUB_ENV
fi
echo "📊 Benchmark Configuration:"
if [ "${{ env.SCHEDULED_RUN }}" = "true" ]; then
echo " Types: lighthouse,bundle-size,source-analysis,build-time,dev-server,resource-usage (scheduled)"
echo " Frameworks: all (scheduled)"
echo " Executions: 5 (scheduled)"
else
echo " Types: ${{ github.event.inputs.benchmark_types || 'all' }}"
echo " Frameworks: ${{ github.event.inputs.frameworks || 'all' }}"
echo " Executions: ${{ github.event.inputs.executions || '1' }}"
fi
echo " Commit to Main: ${{ env.COMMIT_TO_MAIN }}"
- name: 🧪 Run Benchmarks
run: |
set -e # Exit on error
# Configure parameters based on trigger type
if [ "${{ env.SCHEDULED_RUN }}" = "true" ]; then
# Scheduled run: comprehensive benchmarks
benchmark_types="lighthouse,bundle-size,source-analysis,build-time,dev-server,resource-usage"
frameworks="" # All frameworks
executions="5"
echo "⏰ Scheduled run configuration: all benchmarks, all frameworks, 5 executions"
else
# Manual run: use provided inputs
benchmark_types="${{ github.event.inputs.benchmark_types }}"
frameworks="${{ github.event.inputs.frameworks }}"
executions="${{ github.event.inputs.executions }}"
fi
# Build command arguments for the benchmark script
cmd_args=()
cmd_args+=("all") # Run all benchmarks by default
if [ -n "$benchmark_types" ]; then
cmd_args+=("--type" "$benchmark_types")
fi
if [ -n "$frameworks" ]; then
cmd_args+=("--frameworks" "$frameworks")
fi
if [ "$executions" != "1" ] && [ -n "$executions" ]; then
cmd_args+=("--executions" "$executions")
fi
echo "🚀 Running benchmarks: npm run benchmark ${cmd_args[*]}"
# Run benchmarks with retry logic
max_retries=2
retry=0
while [ $retry -le $max_retries ]; do
if [ $retry -gt 0 ]; then
echo "⏳ Retry attempt $retry/$max_retries..."
sleep 10
fi
if npm run benchmark -- "${cmd_args[@]}"; then
echo "✅ Benchmarks completed successfully!"
break
else
exit_code=$?
echo "❌ Benchmarks failed with exit code $exit_code"
if [ $retry -eq $max_retries ]; then
echo "💥 All retry attempts exhausted"
exit $exit_code
fi
retry=$((retry + 1))
# Clean up any hanging processes before retry
pkill -f "chrome" || true
pkill -f "chromium" || true
sleep 5
fi
done
timeout-minutes: 45
- name: 📊 Generate Benchmark Summary
if: always()
run: |
echo "## 📊 Benchmark Results Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Run Date**: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
# Check if benchmarks ran successfully
if [ -d "benchmark-results" ] && [ "$(find benchmark-results -name "*.json" -type f | wc -l)" -gt 0 ]; then
result_count=$(find benchmark-results -name "*.json" -type f | wc -l)
latest_dir=$(find benchmark-results -mindepth 1 -maxdepth 1 -type d | sort -r | head -1)
echo "- **Status**: ✅ Success" >> $GITHUB_STEP_SUMMARY
echo "- **Results Generated**: $result_count files" >> $GITHUB_STEP_SUMMARY
echo "- **Artifacts**: Available for download below" >> $GITHUB_STEP_SUMMARY
if [ -n "$latest_dir" ]; then
echo "- **Latest Results**: $(basename "$latest_dir")" >> $GITHUB_STEP_SUMMARY
fi
else
echo "- **Status**: ❌ Failed" >> $GITHUB_STEP_SUMMARY
echo "- **Reason**: Benchmarks did not complete successfully" >> $GITHUB_STEP_SUMMARY
echo "- **Check**: Review the workflow logs for error details" >> $GITHUB_STEP_SUMMARY
echo "- **Artifacts**: Debug logs may be available below (if any)" >> $GITHUB_STEP_SUMMARY
fi
- name: 📋 Save Workflow Context
run: |
echo '{"commit_to_main": "${{ env.COMMIT_TO_MAIN }}"}' > workflow-context.json
cat workflow-context.json
- name: 📤 Upload Benchmark Results
uses: actions/upload-artifact@v4
if: always()
with:
name: benchmark-results-${{ github.run_number }}
path: |
benchmark-results/
workflow-context.json
!benchmark-results/**/.gitkeep
retention-days: 30
compression-level: 6
- name: 📤 Upload Detailed Logs
uses: actions/upload-artifact@v4
if: failure()
with:
name: benchmark-logs-${{ github.run_number }}
path: |
**/*.log
**/npm-debug.log*
**/yarn-debug.log*
**/yarn-error.log*
retention-days: 7
if-no-files-found: ignore
- name: 🧹 Cleanup
if: always()
run: |
echo "🧹 Cleaning up processes..."
pkill -f "npm.*start" || true
pkill -f "chrome" || true
pkill -f "chromium" || true
echo "✅ Cleanup complete"