Plot Tests: auto/area-basic/plotnine #40
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
| name: "CI: Plot Tests" | |
| run-name: "Plot Tests: ${{ github.head_ref }}" | |
| on: | |
| pull_request: | |
| types: [ opened, synchronize, reopened ] | |
| paths: | |
| - 'plots/**/*.py' | |
| - 'specs/**/*.md' | |
| jobs: | |
| test-plots: | |
| name: Test Plots on Python ${{ matrix.python-version }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: [ '3.11', '3.12', '3.13', '3.14' ] | |
| fail-fast: false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| run: | | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| echo "$HOME/.cargo/bin" >> $GITHUB_PATH | |
| - name: Install dependencies | |
| run: | | |
| uv sync --all-extras | |
| - name: Find changed plot files | |
| id: changed_plots | |
| run: | | |
| # Get list of changed Python files in plots/ | |
| CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'plots/**/*.py' || echo "") | |
| if [ -z "$CHANGED_FILES" ]; then | |
| echo "No plot files changed" | |
| echo "has_plots=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "has_plots=true" >> $GITHUB_OUTPUT | |
| echo "files<<EOF" >> $GITHUB_OUTPUT | |
| echo "$CHANGED_FILES" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| echo "Changed plot files:" | |
| echo "$CHANGED_FILES" | |
| - name: Test plot execution | |
| id: test_execution | |
| if: steps.changed_plots.outputs.has_plots == 'true' | |
| # Only Python 3.14 is required to pass - older versions are compatibility tests | |
| continue-on-error: ${{ matrix.python-version != '3.14' }} | |
| run: | | |
| echo "🧪 Testing plot files on Python ${{ matrix.python-version }}" | |
| FAILED=0 | |
| PASSED=0 | |
| while IFS= read -r file; do | |
| if [ -z "$file" ]; then continue; fi | |
| echo "" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📊 Testing: $file" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| # Run with non-interactive backend | |
| if MPLBACKEND=Agg uv run python "$file" 2>&1; then | |
| echo "✅ PASSED: $file" | |
| PASSED=$((PASSED + 1)) | |
| else | |
| echo "❌ FAILED: $file" | |
| FAILED=$((FAILED + 1)) | |
| fi | |
| done <<< "${{ steps.changed_plots.outputs.files }}" | |
| echo "" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📋 Summary: $PASSED passed, $FAILED failed" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| # Save results for later aggregation | |
| echo "passed=$PASSED" >> $GITHUB_OUTPUT | |
| echo "failed=$FAILED" >> $GITHUB_OUTPUT | |
| if [ $FAILED -gt 0 ]; then | |
| echo "::error::$FAILED plot(s) failed execution on Python ${{ matrix.python-version }}" | |
| exit 1 | |
| fi | |
| - name: Skip message | |
| if: steps.changed_plots.outputs.has_plots != 'true' | |
| run: | | |
| echo "ℹ️ No plot files changed in this PR - skipping tests" | |
| - name: Save test results | |
| if: always() | |
| run: | | |
| mkdir -p test-results | |
| echo "${{ matrix.python-version }},${{ steps.test_execution.outcome || 'skipped' }}" > test-results/result-${{ matrix.python-version }}.txt | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: test-results-${{ matrix.python-version }} | |
| path: test-results/ | |
| retention-days: 30 | |
| # Summary job: post compact PR comment with test results | |
| summary: | |
| name: Post Test Summary | |
| needs: test-plots | |
| if: always() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Download all test results | |
| uses: actions/download-artifact@v6 | |
| with: | |
| pattern: test-results-* | |
| merge-multiple: true | |
| - name: Build summary comment | |
| id: summary | |
| run: | | |
| # Parse results | |
| PY311_RESULT=$(cat result-3.11.txt 2>/dev/null | cut -d',' -f2 || echo "skipped") | |
| PY312_RESULT=$(cat result-3.12.txt 2>/dev/null | cut -d',' -f2 || echo "skipped") | |
| PY313_RESULT=$(cat result-3.13.txt 2>/dev/null | cut -d',' -f2 || echo "skipped") | |
| PY314_RESULT=$(cat result-3.14.txt 2>/dev/null | cut -d',' -f2 || echo "skipped") | |
| # Helper function for badge | |
| badge() { | |
| local version=$1 | |
| local result=$2 | |
| if [ "$result" == "success" ]; then | |
| echo "" | |
| elif [ "$result" == "failure" ]; then | |
| echo "" | |
| else | |
| echo "" | |
| fi | |
| } | |
| # Build comment | |
| if [ "$PY314_RESULT" == "success" ]; then | |
| HEADER="## ✅ Plot Tests Passed" | |
| MAIN_STATUS="**Created with Python 3.14**" | |
| elif [ "$PY314_RESULT" == "failure" ]; then | |
| HEADER="## ❌ Plot Tests Failed" | |
| MAIN_STATUS="**Python 3.14 failed** (required)" | |
| else | |
| HEADER="## ⏭️ Plot Tests Skipped" | |
| MAIN_STATUS="No plot files changed" | |
| fi | |
| # Build badges | |
| B311=$(badge "3.11" "$PY311_RESULT") | |
| B312=$(badge "3.12" "$PY312_RESULT") | |
| B313=$(badge "3.13" "$PY313_RESULT") | |
| cat > /tmp/comment.md << EOF | |
| ${HEADER} | |
| ${MAIN_STATUS} | |
| **Compatibility:** ${B311} ${B312} ${B313} | |
| EOF | |
| cat /tmp/comment.md | |
| echo "has_comment=true" >> $GITHUB_OUTPUT | |
| - name: Post PR comment | |
| if: steps.summary.outputs.has_comment == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const comment = fs.readFileSync('/tmp/comment.md', 'utf8'); | |
| // Find existing bot comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number | |
| }); | |
| const botComment = comments.find(c => | |
| c.user.type === 'Bot' && | |
| c.body.includes('Plot Tests') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: comment | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: comment | |
| }); | |
| } |