Add ability to extract and compile examples both locally and in CI #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-License-Identifier: MIT OR Apache-2.0 | |
| # SPDX-FileCopyrightText: The Coding Guidelines Subcommittee Contributors | |
| name: Check Rust Examples | |
| on: | |
| push: | |
| branches: | |
| - "main" | |
| paths: | |
| - 'src/coding-guidelines/**/*.rst' | |
| - 'tests/rust-examples/**/*.rst' | |
| - 'scripts/extract_rust_examples.py' | |
| - 'scripts/rustdoc_utils.py' | |
| - 'src/examples_prelude.rs' | |
| - '.github/workflows/check-rust-examples.yml' | |
| pull_request: | |
| branches: | |
| - "main" | |
| paths: | |
| - 'src/coding-guidelines/**/*.rst' | |
| - 'tests/rust-examples/**/*.rst' | |
| - 'scripts/extract_rust_examples.py' | |
| - 'scripts/rustdoc_utils.py' | |
| - 'src/examples_prelude.rs' | |
| - '.github/workflows/check-rust-examples.yml' | |
| merge_group: | |
| # Allow running this workflow from other workflows | |
| workflow_call: | |
| jobs: | |
| # Test Rust examples across multiple toolchains | |
| test-examples: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Test with stable (latest) - all examples except nightly-only should pass | |
| - rust: stable | |
| name: Stable (latest) | |
| # Test with an older version to verify version skipping works correctly | |
| - rust: '1.75.0' | |
| name: '1.75.0' | |
| # Test with nightly for channel-specific examples | |
| - rust: nightly | |
| name: Nightly | |
| name: Test Examples (${{ matrix.name }}) | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Install Rust toolchain (${{ matrix.name }}) | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: ${{ matrix.rust }} | |
| - name: Display Rust version | |
| run: | | |
| rustc --version | |
| cargo --version | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v6 | |
| - name: Extract and test Rust examples | |
| id: test-examples | |
| run: | | |
| mkdir -p build/examples | |
| # Run combined extract and test | |
| set +e # Don't exit on error, we want to capture results | |
| uv run python scripts/extract_rust_examples.py \ | |
| --test \ | |
| --src-dir src/coding-guidelines \ | |
| --src-dir tests/rust-examples \ | |
| --prelude src/examples_prelude.rs \ | |
| --json build/examples/results.json \ | |
| --verbose \ | |
| 2>&1 | tee build/examples/test_output.log | |
| EXIT_CODE=$? | |
| # Generate summary | |
| echo "## 🧪 Rust Examples Test Results (${{ matrix.name }})" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Rust version:** \`$(rustc --version)\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -f build/examples/results.json ]; then | |
| TOTAL=$(jq '.total' build/examples/results.json) | |
| PASSED=$(jq '.passed' build/examples/results.json) | |
| FAILED=$(jq '.failed' build/examples/results.json) | |
| SKIPPED=$(jq '.skipped // 0' build/examples/results.json) | |
| if [ "$FAILED" -eq 0 ]; then | |
| if [ "$SKIPPED" -gt 0 ]; then | |
| echo "✅ **$PASSED of $TOTAL examples passed, $SKIPPED skipped**" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "✅ **All $TOTAL examples passed!**" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "❌ **$FAILED of $TOTAL examples failed** ($SKIPPED skipped)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Failed Examples" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| jq -r '.results[] | select(.passed == false) | "- **\(.example.source_file):\(.example.line_number)**: \(.error_message)"' \ | |
| build/examples/results.json >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Show skipped examples if any | |
| if [ "$SKIPPED" -gt 0 ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Skipped Examples" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| jq -r '.results[] | select(.skipped == true) | "- **\(.example.source_file):\(.example.line_number)**: \(.skip_reason)"' \ | |
| build/examples/results.json >> $GITHUB_STEP_SUMMARY 2>/dev/null || true | |
| fi | |
| fi | |
| exit $EXIT_CODE | |
| - name: Upload example test artifacts | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: rust-examples-results-${{ matrix.rust }} | |
| path: | | |
| build/examples/results.json | |
| build/examples/test_output.log | |
| build/examples/examples.json | |
| retention-days: 7 | |
| - name: Annotate failures in PR | |
| if: failure() && github.event_name == 'pull_request' | |
| run: | | |
| if [ -f build/examples/results.json ]; then | |
| jq -r '.results[] | select(.passed == false) | | |
| "::error file=\(.example.source_file),line=\(.example.line_number)::\(.error_message)"' \ | |
| build/examples/results.json | |
| fi | |
| # Aggregate job that requires all example tests to pass | |
| test-examples-complete: | |
| runs-on: ubuntu-latest | |
| needs: test-examples | |
| if: always() | |
| steps: | |
| - name: Check all Rust example tests passed | |
| run: | | |
| if [[ "${{ needs.test-examples.result }}" == "success" ]]; then | |
| echo "✅ All Rust example tests passed across all toolchains!" | |
| else | |
| echo "❌ Some Rust example tests failed" | |
| exit 1 | |
| fi | |
| # Validate rustdoc attribute consistency | |
| check-rustdoc-format: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Check for legacy code blocks | |
| run: | | |
| echo "## 📋 Rustdoc Format Check" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| LEGACY_COUNT=0 | |
| LEGACY_FILES="" | |
| for file in $(find src/coding-guidelines -name "*.rst" 2>/dev/null); do | |
| COUNT=$(grep -c "^\s*\.\. code-block:: rust" "$file" 2>/dev/null || echo 0) | |
| if [ "$COUNT" -gt 0 ]; then | |
| LEGACY_FILES="$LEGACY_FILES\n- $file: $COUNT occurrences" | |
| LEGACY_COUNT=$((LEGACY_COUNT + COUNT)) | |
| fi | |
| done | |
| if [ "$LEGACY_COUNT" -eq 0 ]; then | |
| echo "✅ All Rust code examples use the rust-example:: directive" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "⚠️ **Found $LEGACY_COUNT code blocks using legacy format**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Files with legacy code-block:: rust:" >> $GITHUB_STEP_SUMMARY | |
| echo -e "$LEGACY_FILES" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Consider migrating with: \`uv run python scripts/migrate_rust_examples.py\`" >> $GITHUB_STEP_SUMMARY | |
| fi |