name: E2E Compilation Validation on: push: branches: [ main, develop, "feature/*", "hotfix/*" ] pull_request: branches: [ main, develop ] schedule: # Run nightly at 2 AM UTC for comprehensive validation - cron: '0 2 * * *' workflow_dispatch: inputs: validation_mode: description: 'Validation mode to run' required: true default: 'all' type: choice options: - all - libs - bins - tests - examples - docker continue_on_error: description: 'Continue validation even if some targets fail' required: false default: false type: boolean skip_docker: description: 'Skip Docker validation' required: false default: false type: boolean env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 # Optimize compilation performance CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 RUSTUP_MAX_RETRIES: 10 jobs: setup: name: Setup Environment runs-on: ubuntu-latest outputs: rust-version: ${{ steps.rust-version.outputs.version }} cache-key: ${{ steps.cache-key.outputs.key }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Extract Rust version id: rust-version run: | RUST_VERSION=$(grep '^rust-version' Cargo.toml | sed 's/.*"\([^"]*\)".*/\1/') echo "version=$RUST_VERSION" >> $GITHUB_OUTPUT echo "Detected Rust version: $RUST_VERSION" - name: Generate cache key id: cache-key run: | HASH=$(sha256sum Cargo.lock | cut -d' ' -f1) echo "key=cargo-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-$HASH" >> $GITHUB_OUTPUT validate-compilation: name: E2E Compilation Validation runs-on: ubuntu-latest needs: setup strategy: matrix: validation_mode: - ${{ github.event.inputs.validation_mode || 'all' }} fail-fast: false steps: - name: Checkout repository uses: actions/checkout@v4 - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ needs.setup.outputs.rust-version }} components: clippy, rustfmt - name: Setup sccache uses: mozilla-actions/sccache-action@v0.0.3 with: version: "v0.5.4" - name: Configure sccache run: | echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV - name: Cache Cargo registry and index uses: actions/cache@v4 with: path: | ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ key: ${{ needs.setup.outputs.cache-key }}-registry restore-keys: | cargo-${{ runner.os }}-${{ needs.setup.outputs.rust-version }}- - name: Cache target directory uses: actions/cache@v4 with: path: target/ key: ${{ needs.setup.outputs.cache-key }}-target-${{ matrix.validation_mode }} restore-keys: | ${{ needs.setup.outputs.cache-key }}-target- cargo-${{ runner.os }}-${{ needs.setup.outputs.rust-version }}-target- - name: Setup Docker Buildx if: matrix.validation_mode == 'all' || matrix.validation_mode == 'docker' uses: docker/setup-buildx-action@v3 with: driver-opts: | image=moby/buildkit:buildx-stable-1 install: true - name: Setup Docker layer caching if: matrix.validation_mode == 'all' || matrix.validation_mode == 'docker' uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: buildx-${{ runner.os }}-${{ github.sha }} restore-keys: | buildx-${{ runner.os }}- - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libpq-dev \ protobuf-compiler - name: Build foxhunt-validator run: | cd tools/foxhunt-validator cargo build --release echo "$(pwd)/target/release" >> $GITHUB_PATH - name: Run comprehensive validation id: validation env: CONTINUE_ON_ERROR: ${{ github.event.inputs.continue_on_error || 'false' }} SKIP_DOCKER: ${{ github.event.inputs.skip_docker || 'false' }} VALIDATION_MODE: ${{ matrix.validation_mode }} run: | cd tools/foxhunt-validator # Prepare validation arguments ARGS="" if [ "$CONTINUE_ON_ERROR" = "true" ]; then ARGS="$ARGS --continue-on-error" fi if [ "$SKIP_DOCKER" = "true" ]; then ARGS="$ARGS --skip-docker" fi # Run validation with appropriate mode case "$VALIDATION_MODE" in "all") cargo run --release -- all $ARGS --format json --output /tmp/validation-report.json --verbose ;; "libs") cargo run --release -- libs $ARGS --format json --output /tmp/validation-report.json --verbose ;; "bins") cargo run --release -- bins $ARGS --format json --output /tmp/validation-report.json --verbose ;; "tests") cargo run --release -- tests $ARGS --format json --output /tmp/validation-report.json --verbose ;; "examples") cargo run --release -- examples $ARGS --format json --output /tmp/validation-report.json --verbose ;; "docker") cargo run --release -- docker $ARGS --format json --output /tmp/validation-report.json --verbose ;; *) echo "Unknown validation mode: $VALIDATION_MODE" exit 1 ;; esac - name: Generate HTML report if: always() run: | cd tools/foxhunt-validator if [ -f /tmp/validation-report.json ]; then # Convert JSON report to HTML for better GitHub display cargo run --release -- analyze --format html --output /tmp/validation-report.html fi - name: Upload validation report if: always() uses: actions/upload-artifact@v4 with: name: validation-report-${{ matrix.validation_mode }}-${{ github.run_number }} path: | /tmp/validation-report.json /tmp/validation-report.html retention-days: 30 - name: Process validation results if: always() id: results run: | if [ -f /tmp/validation-report.json ]; then # Extract key metrics from JSON report SUCCESS_RATE=$(jq -r '.summary.success_rate' /tmp/validation-report.json) FAILED_COUNT=$(jq -r '.summary.failed' /tmp/validation-report.json) TIMEOUT_COUNT=$(jq -r '.summary.timed_out' /tmp/validation-report.json) TOTAL_TARGETS=$(jq -r '.summary.total_targets' /tmp/validation-report.json) echo "success_rate=$SUCCESS_RATE" >> $GITHUB_OUTPUT echo "failed_count=$FAILED_COUNT" >> $GITHUB_OUTPUT echo "timeout_count=$TIMEOUT_COUNT" >> $GITHUB_OUTPUT echo "total_targets=$TOTAL_TARGETS" >> $GITHUB_OUTPUT # Determine if validation was successful if [ "$FAILED_COUNT" -eq 0 ] && [ "$TIMEOUT_COUNT" -eq 0 ]; then echo "validation_success=true" >> $GITHUB_OUTPUT else echo "validation_success=false" >> $GITHUB_OUTPUT fi else echo "validation_success=false" >> $GITHUB_OUTPUT echo "No validation report found" fi - name: Comment on PR if: github.event_name == 'pull_request' && always() uses: actions/github-script@v7 with: script: | const fs = require('fs'); let reportContent = "## ๐ŸฆŠ Foxhunt E2E Compilation Validation Report\n\n"; if (fs.existsSync('/tmp/validation-report.json')) { const report = JSON.parse(fs.readFileSync('/tmp/validation-report.json', 'utf8')); const successRate = report.summary.success_rate; const statusEmoji = successRate === 100 ? "โœ…" : successRate >= 95 ? "โš ๏ธ" : "โŒ"; reportContent += `${statusEmoji} **Overall Status**: ${successRate.toFixed(1)}% success rate\n\n`; reportContent += `๐Ÿ“Š **Summary**:\n`; reportContent += `- Total Targets: ${report.summary.total_targets}\n`; reportContent += `- โœ… Successful: ${report.summary.successful}\n`; reportContent += `- โŒ Failed: ${report.summary.failed}\n`; reportContent += `- โฐ Timed Out: ${report.summary.timed_out}\n`; reportContent += `- โญ๏ธ Skipped: ${report.summary.skipped}\n\n`; reportContent += `๐Ÿ“ **Category Breakdown**:\n`; reportContent += `- ๐Ÿ“š Libraries: ${report.categories.libraries.success_rate.toFixed(1)}% (${report.categories.libraries.successful}/${report.categories.libraries.total})\n`; reportContent += `- โšก Binaries: ${report.categories.binaries.success_rate.toFixed(1)}% (${report.categories.binaries.successful}/${report.categories.binaries.total})\n`; reportContent += `- ๐Ÿงช Tests: ${report.categories.tests.success_rate.toFixed(1)}% (${report.categories.tests.successful}/${report.categories.tests.total})\n`; reportContent += `- ๐Ÿ“‹ Examples: ${report.categories.examples.success_rate.toFixed(1)}% (${report.categories.examples.successful}/${report.categories.examples.total})\n`; reportContent += `- ๐Ÿณ Docker: ${report.categories.docker.success_rate.toFixed(1)}% (${report.categories.docker.successful}/${report.categories.docker.total})\n\n`; if (report.summary.failed > 0 || report.summary.timed_out > 0) { reportContent += `โŒ **Failures Detected** - Check the [detailed report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more information.\n\n`; } reportContent += `โฑ๏ธ **Performance**: Total validation time ${(report.total_duration / 1000000000).toFixed(2)}s\n\n`; } else { reportContent += "โŒ **Validation Failed** - No report generated. Check the workflow logs for details.\n\n"; } reportContent += `๐Ÿ”— **Full Report**: [View detailed validation report](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})\n`; reportContent += `๐Ÿ“Š **Validation Mode**: ${{ matrix.validation_mode }}\n`; reportContent += `๐Ÿค– **Generated by**: Foxhunt Validator v0.1.0`; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: reportContent }); - name: Set job status based on validation results if: always() run: | if [ "${{ steps.results.outputs.validation_success }}" = "false" ]; then echo "โŒ Validation failed - some targets did not compile successfully" exit 1 else echo "โœ… All validations passed successfully" fi - name: Print sccache stats if: always() run: sccache --show-stats validation-summary: name: Validation Summary runs-on: ubuntu-latest needs: [setup, validate-compilation] if: always() steps: - name: Download all validation reports uses: actions/download-artifact@v4 with: path: reports/ - name: Create consolidated summary run: | echo "## ๐ŸฆŠ Foxhunt E2E Compilation Validation Summary" >> $GITHUB_STEP_SUMMARY echo "### Validation Results" >> $GITHUB_STEP_SUMMARY for report_dir in reports/*/; do if [ -f "$report_dir/validation-report.json" ]; then MODE=$(basename "$report_dir" | sed 's/validation-report-\(.*\)-[0-9]*/\1/') SUCCESS_RATE=$(jq -r '.summary.success_rate' "$report_dir/validation-report.json") TOTAL=$(jq -r '.summary.total_targets' "$report_dir/validation-report.json") FAILED=$(jq -r '.summary.failed' "$report_dir/validation-report.json") if [ "$FAILED" -eq 0 ]; then echo "- โœ… **$MODE**: $SUCCESS_RATE% ($TOTAL targets)" >> $GITHUB_STEP_SUMMARY else echo "- โŒ **$MODE**: $SUCCESS_RATE% ($FAILED failures out of $TOTAL targets)" >> $GITHUB_STEP_SUMMARY fi fi done echo "### ๐Ÿ“Š Artifacts" >> $GITHUB_STEP_SUMMARY echo "- Detailed JSON and HTML reports available in workflow artifacts" >> $GITHUB_STEP_SUMMARY echo "- Reports retained for 30 days" >> $GITHUB_STEP_SUMMARY notify-failure: name: Notify on Failure runs-on: ubuntu-latest needs: [validate-compilation] if: failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') steps: - name: Notify team of compilation failures uses: actions/github-script@v7 with: script: | const issue_title = `๐Ÿšจ E2E Compilation Validation Failures on ${context.ref.replace('refs/heads/', '')}`; const issue_body = ` ## Compilation Validation Failures Detected **Branch**: \`${context.ref.replace('refs/heads/', '')}\` **Commit**: ${context.sha} **Workflow Run**: https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId} ### โš ๏ธ Action Required Some targets in the workspace are failing to compile. This needs immediate attention to prevent blocking development. ### ๐Ÿ” Investigation Steps 1. Check the [workflow logs](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for detailed error information 2. Download the validation reports from the workflow artifacts 3. Fix compilation issues in failing targets 4. Ensure all tests pass locally before pushing ### ๐Ÿ“‹ Checklist - [ ] Review compilation errors in workflow logs - [ ] Fix failing library crates - [ ] Fix failing binary services - [ ] Fix failing tests - [ ] Fix failing examples - [ ] Fix failing Docker builds - [ ] Verify all validations pass locally - [ ] Push fix and verify CI passes - [ ] Close this issue --- ๐Ÿค– *This issue was automatically created by the E2E Compilation Validation workflow* `; // Check if an issue already exists for this branch const existingIssues = await github.rest.issues.listForRepo({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', labels: 'compilation-failure,automated' }); const existingIssue = existingIssues.data.find(issue => issue.title.includes(context.ref.replace('refs/heads/', '')) ); if (!existingIssue) { await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: issue_title, body: issue_body, labels: ['compilation-failure', 'automated', 'priority-high'] }); }