Migrate #571
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
| # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples | |
| # also derived from https://github.com/we-cli/coverage-badge-action | |
| # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| branches: [main, master] | |
| schedule: | |
| # Runs daily at 2 AM UTC (adjust timezone as needed) | |
| - cron: '0 7 * * *' | |
| workflow_dispatch: | |
| name: test-coverage-local | |
| jobs: | |
| test-coverage: | |
| runs-on: ubuntu-latest | |
| env: | |
| GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} | |
| EARTHDATA_TOKEN: ${{ secrets.EARTHDATA_TOKEN }} | |
| NASA_EARTHDATA_TOKEN: ${{ secrets.EARTHDATA_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| use-public-rspm: true | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| extra-packages: | | |
| any::pak | |
| any::covr | |
| any::rstac | |
| any::testthat | |
| needs: coverage | |
| - name: Cache C++ and R dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cache/R | |
| ~/.local/share/R | |
| key: dependencies-${{ runner.os }}-${{ hashFiles('**/DESCRIPTION') }} | |
| restore-keys: | | |
| dependencies-${{ runner.os }}- | |
| - name: Session info | |
| run: | | |
| options(width = 100) | |
| pkgs <- installed.packages()[, "Package"] | |
| sessioninfo::session_info(pkgs, include_base = TRUE) | |
| shell: Rscript {0} | |
| - name: Test coverage | |
| id: coverage | |
| continue-on-error: true | |
| env: | |
| NOT_CRAN: "false" | |
| run: | | |
| Rscript ${{ github.workspace }}/.github/workflows/test-coverage.R ${{ runner.temp }} ${{ github.workspace }} | |
| shell: bash | |
| - name: Show comprehensive test output | |
| if: always() | |
| run: | | |
| echo "========================================" | |
| echo "SEARCHING FOR ALL TEST OUTPUT FILES" | |
| echo "========================================" | |
| echo "" | |
| echo "=== Files in runner.temp ===" | |
| find ${{ runner.temp }} -type f -name "*.Rout*" 2>/dev/null || echo "No .Rout files found" | |
| echo "" | |
| echo "=== Files in workspace ===" | |
| find ${{ github.workspace }} -type f -name "*.Rout*" 2>/dev/null || echo "No .Rout files found" | |
| echo "" | |
| echo "========================================" | |
| echo "CONTENT OF FAILURE FILE" | |
| echo "========================================" | |
| FAIL_FILE=$(find ${{ runner.temp }} -name "testthat.Rout.fail" -type f 2>/dev/null | head -1) | |
| if [ -n "$FAIL_FILE" ]; then | |
| echo "Found failure file: $FAIL_FILE" | |
| echo "--- START OF FILE ---" | |
| cat "$FAIL_FILE" | |
| echo "--- END OF FILE ---" | |
| else | |
| echo "No testthat.Rout.fail file found" | |
| fi | |
| echo "" | |
| echo "========================================" | |
| echo "CONTENT OF SUCCESS FILE" | |
| echo "========================================" | |
| SUCCESS_FILE=$(find ${{ runner.temp }} -name "testthat.Rout" -type f 2>/dev/null | head -1) | |
| if [ -n "$SUCCESS_FILE" ]; then | |
| echo "Found success file: $SUCCESS_FILE" | |
| echo "--- START OF FILE ---" | |
| cat "$SUCCESS_FILE" | |
| echo "--- END OF FILE ---" | |
| else | |
| echo "No testthat.Rout file found" | |
| fi | |
| echo "" | |
| echo "========================================" | |
| echo "CONTENT OF RES FILES" | |
| echo "========================================" | |
| find ${{ runner.temp }} -name "*.Rout.res" -type f 2>/dev/null | while read -r file; do | |
| echo "File: $file" | |
| echo "--- START ---" | |
| cat "$file" | |
| echo "--- END ---" | |
| echo "" | |
| done || echo "No .Rout.res files found" | |
| echo "" | |
| echo "========================================" | |
| echo "PACKAGE DIRECTORY STRUCTURE" | |
| echo "========================================" | |
| echo "Contents of ${{ runner.temp }}/package:" | |
| ls -laR ${{ runner.temp }}/package 2>/dev/null || echo "Directory not found" | |
| echo "" | |
| echo "========================================" | |
| echo "COVERAGE OUTPUT FILE" | |
| echo "========================================" | |
| if [ -f "${{ github.workspace }}/local_cov.Rout" ]; then | |
| echo "Coverage file exists:" | |
| cat ${{ github.workspace }}/local_cov.Rout | |
| else | |
| echo "Coverage file NOT found at ${{ github.workspace }}/local_cov.Rout" | |
| fi | |
| echo "" | |
| echo "========================================" | |
| echo "ALL .Rout FILES CONTENT" | |
| echo "========================================" | |
| find ${{ runner.temp }} -type f -name "*.Rout*" 2>/dev/null | while read -r file; do | |
| echo "" | |
| echo "========== FILE: $file ==========" | |
| head -n 200 "$file" 2>/dev/null || echo "Could not read file" | |
| if [ $(wc -l < "$file" 2>/dev/null || echo 0) -gt 200 ]; then | |
| echo "... (file truncated, showing first 200 lines) ..." | |
| fi | |
| done || echo "No .Rout files to display" | |
| shell: bash | |
| - name: Check if coverage file exists | |
| id: check-coverage-file | |
| if: always() | |
| run: | | |
| if [ -f "${{ github.workspace }}/local_cov.Rout" ]; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| echo "Coverage file exists" | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| echo "Coverage file does NOT exist - creating with 0" | |
| echo "0" > ${{ github.workspace }}/local_cov.Rout | |
| fi | |
| shell: bash | |
| - name: Get Values | |
| id: get-values | |
| if: always() | |
| shell: bash | |
| run: | | |
| if [ -f "${{ github.workspace }}/local_cov.Rout" ]; then | |
| COV=$(cat ${{ github.workspace }}/local_cov.Rout | tr -d '[:space:]') | |
| if [ -z "$COV" ]; then | |
| echo "Coverage file is empty, using 0" | |
| COV="0" | |
| fi | |
| else | |
| echo "Coverage file not found, using 0" | |
| COV="0" | |
| fi | |
| echo "Patch coverage read from local_cov.Rout: $COV" | |
| echo "coverage=$COV" >> $GITHUB_OUTPUT | |
| - name: Fail if coverage calculation failed | |
| if: steps.coverage.outcome == 'failure' | |
| run: | | |
| echo "::error::Coverage calculation failed. Check the test output above for details." | |
| exit 1 | |
| - name: Checkout gh-pages | |
| id: checkout-gh-pages | |
| if: steps.coverage.outcome == 'success' | |
| uses: actions/checkout@v4 | |
| continue-on-error: true | |
| with: | |
| ref: gh-pages | |
| - name: Patch comparison | |
| if: steps.coverage.outcome == 'success' | |
| id: patch-comparison | |
| shell: bash | |
| run: | | |
| cov_patch="${{ steps.get-values.outputs.coverage }}" | |
| # Check if gh-pages checkout succeeded and file exists | |
| if [[ "${{ steps.checkout-gh-pages.outcome }}" == "success" ]] && test -f cov_current.Rout; then | |
| cov_current=$(cat cov_current.Rout) | |
| echo "Current coverage: $cov_current" | |
| else | |
| echo "No gh-pages branch or cov_current.Rout found. Setting current coverage to 0." | |
| cov_current=0 | |
| fi | |
| echo "Patch coverage: $cov_patch" | |
| # Pass if coverage exceeds 99%, is at least current coverage, | |
| # or is within a small tolerance to absorb platform-specific | |
| # variability in total coverage calculations. | |
| tolerance=0.5 | |
| cov_floor=$(echo "$cov_current - $tolerance" | bc -l) | |
| if (( $(echo "$cov_patch > 99" | bc -l) )); then | |
| echo "✓ Patch coverage ($cov_patch%) exceeds 99% threshold." | |
| echo "cov_update=$cov_patch" >> $GITHUB_OUTPUT | |
| elif (( $(echo "$cov_patch >= $cov_current" | bc -l) )); then | |
| echo "✓ Patch coverage ($cov_patch%) is greater than or equal to current coverage ($cov_current%)." | |
| echo "cov_update=$cov_patch" >> $GITHUB_OUTPUT | |
| elif (( $(echo "$cov_patch >= $cov_floor" | bc -l) )); then | |
| echo "::warning::Patch coverage ($cov_patch%) is below current coverage ($cov_current%)" | |
| echo "::warning::but within allowed tolerance ($tolerance%)." | |
| echo "cov_update=$cov_current" >> $GITHUB_OUTPUT | |
| else | |
| echo "::error::Patch coverage ($cov_patch%) is less than" | |
| echo "::error::current coverage floor ($cov_floor%) and below 99%." | |
| echo "::error::This indicates that new code is not adequately tested or existing coverage was reduced." | |
| exit 1 | |
| fi | |
| - name: Overwrite cov_current.Rout | |
| if: ${{ github.event_name == 'push' && steps.coverage.outcome == 'success' }} | |
| shell: bash | |
| run: | | |
| cov_update="${{ steps.patch-comparison.outputs.cov_update }}" | |
| touch cov_current.Rout | |
| echo "$cov_update" > cov_current.Rout | |
| echo "Updated cov_current.Rout with: $cov_update" | |
| - name: Create Badges | |
| if: steps.coverage.outcome == 'success' | |
| shell: bash | |
| run: | | |
| npm i -g badgen-cli | |
| export COV=${{ steps.get-values.outputs.coverage }} | |
| echo "Creating badge with coverage: $COV%" | |
| # Determine color based on coverage | |
| if (( $(echo "$COV >= 95" | bc -l) )); then | |
| COLOR="green" | |
| elif (( $(echo "$COV >= 80" | bc -l) )); then | |
| COLOR="yellow" | |
| elif (( $(echo "$COV >= 60" | bc -l) )); then | |
| COLOR="orange" | |
| else | |
| COLOR="red" | |
| fi | |
| echo "Badge color: $COLOR" | |
| mkdir -p badges | |
| badgen -j coverage -s "$COV%" -c "$COLOR" > badges/coverage.svg | |
| - name: Deploy Badges | |
| if: steps.coverage.outcome == 'success' | |
| uses: stefanzweifel/git-auto-commit-action@v4 | |
| with: | |
| commit_message: "Update badges [skip ci] & cov_current.Rout" | |
| branch: gh-pages | |
| skip_fetch: true | |
| skip_checkout: true | |
| create_branch: true | |
| - name: Checkout Back | |
| if: always() | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.ref }} | |
| - name: Final Summary | |
| if: always() | |
| run: | | |
| echo "========================================" | |
| echo "WORKFLOW SUMMARY" | |
| echo "========================================" | |
| echo "Coverage calculation: ${{ steps.coverage.outcome }}" | |
| echo "Coverage value: ${{ steps.get-values.outputs.coverage }}%" | |
| echo "Coverage file exists: ${{ steps.check-coverage-file.outputs.exists }}" | |
| if [ "${{ steps.coverage.outcome }}" == "failure" ]; then | |
| echo "" | |
| echo "❌ Coverage calculation FAILED" | |
| echo "Please review the test output above to identify the failing tests" | |
| else | |
| echo "" | |
| echo "✅ Coverage calculation SUCCEEDED" | |
| fi | |
| shell: bash |