coverage: Ignore errors files #190
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: Code Coverage | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| pull-requests: write | |
| concurrency: | |
| group: coverage-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| coverage: | |
| name: Generate Coverage Report | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: llvm-tools-preview | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Install cargo-tarpaulin | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-tarpaulin | |
| - name: Install grcov for merging coverage | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: grcov | |
| - name: Install system dependencies and setup D-Bus | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libssl-dev pkg-config gnome-keyring dbus-x11 jq | |
| # Start D-Bus session | |
| mkdir -p ~/.local/share/keyrings | |
| eval $(dbus-launch --sh-syntax) | |
| export DBUS_SESSION_BUS_ADDRESS | |
| echo "DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS" >> $GITHUB_ENV | |
| # Initialize and unlock the default keyring | |
| printf '\n' | gnome-keyring-daemon --unlock --daemonize --login | |
| # Give the service time to start | |
| sleep 3 | |
| - name: Run coverage script | |
| run: | | |
| chmod +x coverage.sh | |
| ./coverage.sh | |
| - name: Prepare coverage for deployment | |
| run: | | |
| mkdir -p site/coverage | |
| cp -r coverage/* site/coverage/ | |
| # Extract coverage percentage from the generated JSON file | |
| CURRENT_COVERAGE=$(jq -r '.message' site/coverage/html/coverage.json | sed 's/%//') | |
| echo "CURRENT_COVERAGE=$CURRENT_COVERAGE" >> $GITHUB_ENV | |
| echo "Combined coverage: $CURRENT_COVERAGE%" | |
| - name: Generate coverage summary for PR comparison | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| echo "PR_COVERAGE=$CURRENT_COVERAGE" >> $GITHUB_ENV | |
| echo "PR coverage: $CURRENT_COVERAGE%" | |
| - name: Store coverage percentage for main branch | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| run: | | |
| echo "Main branch coverage: $CURRENT_COVERAGE%" | |
| # Store in a simple text file artifact for PR comparisons | |
| mkdir -p coverage-baseline | |
| echo "$CURRENT_COVERAGE" > coverage-baseline/main-coverage.txt | |
| # Generate coverage badge | |
| COVERAGE_INT=$(echo "$CURRENT_COVERAGE" | cut -d. -f1) | |
| if [ "$COVERAGE_INT" -ge 80 ]; then | |
| COLOR="brightgreen" | |
| elif [ "$COVERAGE_INT" -ge 60 ]; then | |
| COLOR="yellow" | |
| else | |
| COLOR="red" | |
| fi | |
| # Create badge SVG using shields.io format | |
| curl -s "https://img.shields.io/badge/coverage-${CURRENT_COVERAGE}%25-${COLOR}" > site/coverage/badge.svg | |
| - name: Upload baseline coverage | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: coverage-baseline | |
| path: coverage-baseline/main-coverage.txt | |
| retention-days: 90 | |
| - name: Get main branch coverage for comparison | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| // Find the latest successful coverage run on main that has the baseline artifact | |
| const { data: runs } = await github.rest.actions.listWorkflowRuns({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'coverage.yml', | |
| status: 'completed', | |
| conclusion: 'success', | |
| branch: 'main', | |
| per_page: 10 | |
| }); | |
| for (const run of runs.workflow_runs) { | |
| try { | |
| const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: run.id | |
| }); | |
| const baselineArtifact = artifacts.artifacts.find(a => a.name === 'coverage-baseline'); | |
| if (baselineArtifact) { | |
| core.exportVariable('BASELINE_RUN_ID', run.id.toString()); | |
| console.log(`Found baseline artifact in run ${run.id}`); | |
| return; | |
| } | |
| } catch (error) { | |
| console.log(`Error checking run ${run.id}: ${error.message}`); | |
| } | |
| } | |
| console.log('No baseline artifact found in recent main branch runs'); | |
| core.exportVariable('BASELINE_RUN_ID', ''); | |
| - name: Download baseline artifact | |
| if: github.event_name == 'pull_request' && env.BASELINE_RUN_ID != '' | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: coverage-baseline | |
| path: coverage-baseline/ | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-id: ${{ env.BASELINE_RUN_ID }} | |
| continue-on-error: true | |
| - name: Set main coverage for comparison | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| if [ -f coverage-baseline/main-coverage.txt ]; then | |
| MAIN_COVERAGE=$(cat coverage-baseline/main-coverage.txt) | |
| echo "MAIN_COVERAGE=$MAIN_COVERAGE" >> $GITHUB_ENV | |
| echo "Using stored main branch coverage: $MAIN_COVERAGE%" | |
| else | |
| echo "MAIN_COVERAGE=0.00" >> $GITHUB_ENV | |
| echo "No baseline coverage found, using 0.00%" | |
| fi | |
| - name: Post coverage comment on PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const prCoverage = parseFloat(process.env.PR_COVERAGE || '0.00'); | |
| const mainCoverage = parseFloat(process.env.MAIN_COVERAGE || '0.00'); | |
| const diff = prCoverage - mainCoverage; | |
| const diffText = diff > 0 ? `+${diff.toFixed(2)}%` : `${diff.toFixed(2)}%`; | |
| const emoji = diff > 0 ? '📈' : diff < 0 ? '📉' : '➡️'; | |
| const body = `## 📊 Code Coverage Report | |
| | Metric | Value | | |
| |--------|-------| | |
| | **Current PR Coverage** | ${prCoverage.toFixed(2)}% | | |
| | **Main Branch Coverage** | ${mainCoverage.toFixed(2)}% | | |
| | **Coverage Change** | ${emoji} ${diffText} | | |
| ${diff < -1 ? '⚠️ **Warning**: Coverage decreased by more than 1%' : ''} | |
| ${diff > 1 ? '🎉 **Great**: Coverage increased by more than 1%!' : ''} | |
| *Coverage report generated by [cargo-tarpaulin](https://github.com/xd009642/tarpaulin)*`; | |
| // Find existing coverage comment | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const existingComment = comments.find(comment => | |
| comment.body.includes('## 📊 Code Coverage Report') | |
| ); | |
| if (existingComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existingComment.id, | |
| body: body | |
| }); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: body | |
| }); | |
| } | |
| - name: Upload coverage artifacts | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: coverage-reports | |
| path: site/coverage/html/ | |
| retention-days: 30 |