Skip to content

Test Ruchy Book Examples #563

Test Ruchy Book Examples

Test Ruchy Book Examples #563

Workflow file for this run

name: Test Ruchy Book Examples
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
# Run daily at midnight UTC to catch regressions
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
ruchy_version:
description: 'Ruchy version to test (leave empty for latest)'
required: false
default: ''
jobs:
test-book-comprehensive:
name: Test Book Examples (v${{ matrix.ruchy_version || 'latest' }})
runs-on: ubuntu-latest
strategy:
matrix:
ruchy_version: ['1.69.0'] # Pin to latest stable
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Ruchy from crates.io
run: |
if [ -n "${{ github.event.inputs.ruchy_version }}" ]; then
cargo install ruchy --version ${{ github.event.inputs.ruchy_version }} --force
elif [ -n "${{ matrix.ruchy_version }}" ]; then
cargo install ruchy --version ${{ matrix.ruchy_version }} --force
else
cargo install ruchy --force
fi
ruchy --version
- name: Install Deno
uses: denoland/setup-deno@v1
with:
deno-version: v2.x
- name: Install mdBook
run: |
curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.37/mdbook-v0.4.37-x86_64-unknown-linux-gnu.tar.gz | tar -xz
chmod +x mdbook
sudo mv mdbook /usr/local/bin/
mdbook --version
- name: Run comprehensive tests
id: test
run: |
echo "πŸ§ͺ Running comprehensive test suite..."
make test > test_output.log 2>&1 || true
cat test_output.log
# Extract statistics from logs
TOTAL_EXAMPLES=$(grep -o "Code examples found: [0-9]*" test_output.log | grep -o "[0-9]*" || echo "0")
PASSING_EXAMPLES=$(grep -o "Examples working: [0-9]*" test_output.log | grep -o "[0-9]*" || echo "0")
FAILING_EXAMPLES=$(grep -o "Examples failing: [0-9]*" test_output.log | grep -o "[0-9]*" || echo "0")
SUCCESS_RATE=$(grep -o "Success rate: [0-9]*%" test_output.log | grep -o "[0-9]*" || echo "0")
echo "total_examples=$TOTAL_EXAMPLES" >> $GITHUB_OUTPUT
echo "passing_examples=$PASSING_EXAMPLES" >> $GITHUB_OUTPUT
echo "failing_examples=$FAILING_EXAMPLES" >> $GITHUB_OUTPUT
echo "success_rate=$SUCCESS_RATE" >> $GITHUB_OUTPUT
# Set status based on success rate
if [ "$SUCCESS_RATE" -ge 60 ]; then
echo "status=success" >> $GITHUB_OUTPUT
echo "status_emoji=βœ…" >> $GITHUB_OUTPUT
echo "status_color=green" >> $GITHUB_OUTPUT
elif [ "$SUCCESS_RATE" -ge 40 ]; then
echo "status=warning" >> $GITHUB_OUTPUT
echo "status_emoji=⚠️" >> $GITHUB_OUTPUT
echo "status_color=yellow" >> $GITHUB_OUTPUT
else
echo "status=failure" >> $GITHUB_OUTPUT
echo "status_emoji=❌" >> $GITHUB_OUTPUT
echo "status_color=red" >> $GITHUB_OUTPUT
fi
- name: Test one-liners separately
id: oneliners
run: |
echo "🎯 Testing one-liner examples..."
deno task test-oneliners > oneliners.log 2>&1 || true
cat oneliners.log
# Extract one-liner stats
ONELINERS_PASS=$(grep -o "Tests Passed: [0-9]*" oneliners.log | grep -o "[0-9]*" || echo "0")
ONELINERS_FAIL=$(grep -o "Tests Failed: [0-9]*" oneliners.log | grep -o "[0-9]*" || echo "0")
ONELINERS_TOTAL=$(( ONELINERS_PASS + ONELINERS_FAIL ))
echo "oneliners_pass=$ONELINERS_PASS" >> $GITHUB_OUTPUT
echo "oneliners_fail=$ONELINERS_FAIL" >> $GITHUB_OUTPUT
echo "oneliners_total=$ONELINERS_TOTAL" >> $GITHUB_OUTPUT
- name: Run dogfooding quality gates
id: dogfood
run: |
echo "πŸ• Running dogfooding quality gates..."
make dogfood-quick > dogfood.log 2>&1 || true
cat dogfood.log
# Extract dogfood stats
CHECK_PASS=$(grep -o "ruchy check.*: [0-9]* passed" dogfood.log | grep -o "[0-9]* passed" | grep -o "[0-9]*" || echo "0")
LINT_PASS=$(grep -o "ruchy lint.*: [0-9]* passed" dogfood.log | grep -o "[0-9]* passed" | grep -o "[0-9]*" || echo "0")
echo "check_pass=$CHECK_PASS" >> $GITHUB_OUTPUT
echo "lint_pass=$LINT_PASS" >> $GITHUB_OUTPUT
- name: Generate test badges
id: badges
run: |
# Create badge data directory
mkdir -p badges
# Overall test status badge
echo "{\"schemaVersion\": 1, \"label\": \"tests\", \"message\": \"${{ steps.test.outputs.success_rate }}%\", \"color\": \"${{ steps.test.outputs.status_color }}\"}" > badges/tests.json
# Book examples badge
BOOK_PERCENT="${{ steps.test.outputs.success_rate }}"
BOOK_COLOR="red"
[ "$BOOK_PERCENT" -ge 40 ] && BOOK_COLOR="yellow"
[ "$BOOK_PERCENT" -ge 60 ] && BOOK_COLOR="green"
echo "{\"schemaVersion\": 1, \"label\": \"book examples\", \"message\": \"${{ steps.test.outputs.passing_examples }}/${{ steps.test.outputs.total_examples }} (${BOOK_PERCENT}%)\", \"color\": \"$BOOK_COLOR\"}" > badges/book-examples.json
# One-liners badge
ONELINER_PERCENT=0
if [ "${{ steps.oneliners.outputs.oneliners_total }}" -gt 0 ]; then
ONELINER_PERCENT=$((100 * ${{ steps.oneliners.outputs.oneliners_pass }} / ${{ steps.oneliners.outputs.oneliners_total }}))
fi
ONELINER_COLOR="red"
[ "$ONELINER_PERCENT" -ge 50 ] && ONELINER_COLOR="yellow"
[ "$ONELINER_PERCENT" -ge 80 ] && ONELINER_COLOR="green"
echo "{\"schemaVersion\": 1, \"label\": \"one-liners\", \"message\": \"${{ steps.oneliners.outputs.oneliners_pass }}/${{ steps.oneliners.outputs.oneliners_total }} (${ONELINER_PERCENT}%)\", \"color\": \"$ONELINER_COLOR\"}" > badges/oneliners.json
# Quality gates badge
echo "{\"schemaVersion\": 1, \"label\": \"quality\", \"message\": \"check: ${{ steps.dogfood.outputs.check_pass }} | lint: ${{ steps.dogfood.outputs.lint_pass }}\", \"color\": \"blue\"}" > badges/quality.json
# Create README badge snippet
cat > badges/README_SNIPPET.md <<'EOF'
![Tests](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/paiml/ruchy-book/badges/tests.json)
![Book Examples](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/paiml/ruchy-book/badges/book-examples.json)
![One-liners](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/paiml/ruchy-book/badges/oneliners.json)
![Quality](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/paiml/ruchy-book/badges/quality.json)
EOF
echo "Generated badge files in badges/"
ls -la badges/
- name: Update README with current status
if: github.ref == 'refs/heads/main'
run: |
# Update README.md with current test results
README_FILE="README.md"
# Calculate percentages for display
BOOK_PERCENT="${{ steps.test.outputs.success_rate }}"
ONELINER_PERCENT=0
if [ "${{ steps.oneliners.outputs.oneliners_total }}" -gt 0 ]; then
ONELINER_PERCENT=$((100 * ${{ steps.oneliners.outputs.oneliners_pass }} / ${{ steps.oneliners.outputs.oneliners_total }}))
fi
# Update the Current Status section in README
sed -i '/### Current Status (Auto-Updated)/,/^###\|^##/c\### Current Status (Auto-Updated)\n\n<!-- STATUS_START -->\n**Last Updated**: '"$(date -u '+%Y-%m-%d %H:%M UTC')"'\n**Ruchy Version**: v1.84.0\n\n- πŸ“Š **Book Examples**: ${{ steps.test.outputs.passing_examples }}/${{ steps.test.outputs.total_examples }} passing ('"${BOOK_PERCENT}"'%)\n- 🎯 **One-liners**: ${{ steps.oneliners.outputs.oneliners_pass }}/${{ steps.oneliners.outputs.oneliners_total }} passing ('"${ONELINER_PERCENT}"'%)\n- βœ… **Quality Gates**: ${{ steps.dogfood.outputs.check_pass }} files pass syntax check, ${{ steps.dogfood.outputs.lint_pass }} files pass lint\n- πŸš€ **CI Status**: ${{ steps.test.outputs.status_emoji }} ${{ steps.test.outputs.status }}\n<!-- STATUS_END -->\n\n###' README.md || true
# If the sed didn't find the section, append it after the badges
if ! grep -q "STATUS_START" README.md; then
# Find line after badges and insert status
sed -i '/^## 🎯 \*\*CRITICAL: Test-Driven Transformation\*\*/a\\n### Current Status (Auto-Updated)\n\n<!-- STATUS_START -->\n**Last Updated**: '"$(date -u '+%Y-%m-%d %H:%M UTC')"'\n**Ruchy Version**: v1.84.0\n\n- πŸ“Š **Book Examples**: ${{ steps.test.outputs.passing_examples }}/${{ steps.test.outputs.total_examples }} passing ('"${BOOK_PERCENT}"'%)\n- 🎯 **One-liners**: ${{ steps.oneliners.outputs.oneliners_pass }}/${{ steps.oneliners.outputs.oneliners_total }} passing ('"${ONELINER_PERCENT}"'%)\n- βœ… **Quality Gates**: ${{ steps.dogfood.outputs.check_pass }} files pass syntax check, ${{ steps.dogfood.outputs.lint_pass }} files pass lint\n- πŸš€ **CI Status**: ${{ steps.test.outputs.status_emoji }} ${{ steps.test.outputs.status }}\n<!-- STATUS_END -->' README.md
fi
echo "README.md updated with current status"
- name: Deploy badges to GitHub Pages
if: github.ref == 'refs/heads/main'
run: |
# Configure git
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
# Clone the repository to a temporary directory
git clone --single-branch --branch main https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git temp-badges
cd temp-badges
# Create or switch to badges branch
git checkout badges 2>/dev/null || git checkout -b badges
# Copy badge files
cp -r ../badges/* .
# Add and commit if there are changes
git add -A
if ! git diff --cached --quiet; then
git commit -m "Update test badges - run #${{ github.run_number }}"
git push origin badges --force
echo "βœ… Badges deployed to badges branch"
else
echo "No changes to badges"
fi
- name: Commit README updates
if: github.ref == 'refs/heads/main'
run: |
# Configure git
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"
# Check if README was modified
if ! git diff --quiet README.md; then
git add README.md
COMMIT_MSG="docs: Auto-update README status from CI run #${{ github.run_number }}"
COMMIT_MSG="$COMMIT_MSG - Book: ${{ steps.test.outputs.passing_examples }}/${{ steps.test.outputs.total_examples }} (${{ steps.test.outputs.success_rate }}%)"
COMMIT_MSG="$COMMIT_MSG, One-liners: ${{ steps.oneliners.outputs.oneliners_pass }}/${{ steps.oneliners.outputs.oneliners_total }}"
git commit -m "$COMMIT_MSG"
git push origin main
echo "βœ… README.md updated and pushed"
else
echo "No changes to README.md"
fi
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ github.run_number }}
path: |
test_output.log
oneliners.log
dogfood.log
test/extracted-examples/
reports/
badges/
retention-days: 30
- name: Create job summary
if: always()
run: |
cat >> $GITHUB_STEP_SUMMARY <<EOF
# πŸ“š Ruchy Book Test Results
**Ruchy Version:** $(ruchy --version)
**Status:** ${{ steps.test.outputs.status_emoji }} ${{ steps.test.outputs.status }}
## πŸ“Š Overall Statistics
| Metric | Value |
|--------|-------|
| Total Examples | ${{ steps.test.outputs.total_examples }} |
| Passing | ${{ steps.test.outputs.passing_examples }} |
| Failing | ${{ steps.test.outputs.failing_examples }} |
| **Success Rate** | **${{ steps.test.outputs.success_rate }}%** |
## 🎯 One-Liner Tests
| Metric | Value |
|--------|-------|
| Total | ${{ steps.oneliners.outputs.oneliners_total }} |
| Passing | ${{ steps.oneliners.outputs.oneliners_pass }} |
| Failing | ${{ steps.oneliners.outputs.oneliners_fail }} |
## πŸ• Dogfooding Quality Gates
| Tool | Result |
|------|--------|
| ruchy check | ${{ steps.dogfood.outputs.check_pass }} files pass |
| ruchy lint | ${{ steps.dogfood.outputs.lint_pass }} files pass |
---
[πŸ“‹ View Full Logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})
EOF
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const comment = `## πŸ“š Ruchy Book Test Results
**Status:** ${{ steps.test.outputs.status_emoji }} Tests are **${{ steps.test.outputs.status }}**
πŸ“Š **Book Examples:** ${{ steps.test.outputs.passing_examples }}/${{ steps.test.outputs.total_examples }} passing (${{ steps.test.outputs.success_rate }}%)
🎯 **One-liners:** ${{ steps.oneliners.outputs.oneliners_pass }}/${{ steps.oneliners.outputs.oneliners_total }} passing
πŸ• **Quality Gates:** βœ… ${{ steps.dogfood.outputs.check_pass }} files pass syntax check, ${{ steps.dogfood.outputs.lint_pass }} files pass linting
[View Full Test Report β†’](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
- name: Fail if tests are failing
if: steps.test.outputs.status == 'failure'
run: |
echo "❌ Tests failed with success rate of ${{ steps.test.outputs.success_rate }}%"
echo "Threshold is 40% for CI to pass"
exit 1