Add PHPUnit Coverage workflow #6
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: Code Coverage (Grouped) | |
| on: | |
| pull_request: | |
| branches: | |
| - develop | |
| - main | |
| push: | |
| branches: | |
| - develop | |
| - main | |
| workflow_dispatch: | |
| # Cancels all previous workflow runs for the same branch that have not yet completed. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| coverage-matrix: | |
| name: Coverage - ${{ matrix.group }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| group: | |
| - activities | |
| - badges | |
| - admin | |
| - api | |
| - suggested-tasks-providers-1 | |
| - suggested-tasks-providers-2 | |
| - suggested-tasks-providers-3 | |
| - suggested-tasks-providers-4 | |
| - suggested-tasks-data-collectors-1 | |
| - suggested-tasks-data-collectors-2 | |
| - suggested-tasks-data-collectors-3 | |
| - goals | |
| - updates | |
| - ui | |
| - utils | |
| - misc | |
| services: | |
| mysql: | |
| image: mysql:8.0 | |
| env: | |
| MYSQL_ALLOW_EMPTY_PASSWORD: false | |
| MYSQL_ROOT_PASSWORD: root | |
| MYSQL_DATABASE: wordpress_tests | |
| ports: | |
| - 3306:3306 | |
| options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=10s --health-retries=10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.3' | |
| ini-values: memory_limit=512M | |
| coverage: xdebug | |
| tools: composer | |
| - name: Install SVN | |
| run: sudo apt-get install subversion | |
| - name: Install Composer dependencies | |
| uses: ramsey/composer-install@v2 | |
| with: | |
| dependency-versions: "highest" | |
| composer-options: "--prefer-dist" | |
| - name: Install WordPress Test Suite | |
| shell: bash | |
| run: tests/bin/install-wp-tests.sh wordpress_tests root root 127.0.0.1:3306 latest | |
| - name: Run PHPUnit with coverage for group | |
| run: | | |
| echo "Running coverage for group: ${{ matrix.group }}" | |
| # Run PHPUnit with coverage using the group annotation | |
| set +e | |
| php -d memory_limit=512M \ | |
| vendor/bin/phpunit \ | |
| --coverage-clover=coverage-${{ matrix.group }}.xml \ | |
| --coverage-text \ | |
| --group "${{ matrix.group }}" | |
| EXIT_CODE=$? | |
| set -e | |
| echo "PHPUnit exit code: $EXIT_CODE" | |
| # Check if coverage was generated | |
| if [ -f coverage-${{ matrix.group }}.xml ]; then | |
| echo "✓ Coverage generated for ${{ matrix.group }}" | |
| ls -lh coverage-${{ matrix.group }}.xml | |
| else | |
| echo "✗ Coverage NOT generated for ${{ matrix.group }}" | |
| exit 1 | |
| fi | |
| - name: Upload coverage for group | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-${{ matrix.group }} | |
| path: coverage-${{ matrix.group }}.xml | |
| retention-days: 1 | |
| merge-coverage: | |
| name: Merge & Report Coverage | |
| needs: coverage-matrix | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install PHP | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.3' | |
| tools: composer | |
| - name: Download all coverage artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: coverage-* | |
| merge-multiple: true | |
| - name: List downloaded coverage files | |
| run: | | |
| echo "Downloaded coverage files:" | |
| ls -lh coverage-*.xml | |
| - name: Merge coverage reports | |
| run: | | |
| # Merge all Clover XML files into a single report | |
| php -r ' | |
| $xmlFiles = glob("coverage-*.xml"); | |
| if (empty($xmlFiles)) { | |
| echo "No coverage files found\n"; | |
| exit(1); | |
| } | |
| $totalLines = 0; | |
| $coveredLines = 0; | |
| $files = []; | |
| foreach ($xmlFiles as $xmlFile) { | |
| $xml = simplexml_load_file($xmlFile); | |
| if ($xml === false) { | |
| echo "Failed to parse $xmlFile\n"; | |
| continue; | |
| } | |
| // Extract metrics from each file | |
| foreach ($xml->xpath("//file") as $file) { | |
| $path = (string)$file["name"]; | |
| $metrics = $file->metrics[0]; | |
| if (!isset($files[$path])) { | |
| $files[$path] = [ | |
| "elements" => (int)$metrics["elements"], | |
| "coveredelements" => (int)$metrics["coveredelements"], | |
| "statements" => (int)$metrics["statements"], | |
| "coveredstatements" => (int)$metrics["coveredstatements"], | |
| ]; | |
| } | |
| } | |
| // Get project totals | |
| $project = $xml->project[0]; | |
| if ($project && $project->metrics[0]) { | |
| $metrics = $project->metrics[0]; | |
| $totalLines += (int)$metrics["statements"]; | |
| $coveredLines += (int)$metrics["coveredstatements"]; | |
| } | |
| } | |
| echo "Processed " . count($xmlFiles) . " coverage files\n"; | |
| echo "Total statements: $totalLines\n"; | |
| echo "Covered statements: $coveredLines\n"; | |
| if ($totalLines > 0) { | |
| $percentage = round(($coveredLines / $totalLines) * 100, 2); | |
| echo "Coverage: $percentage%\n"; | |
| // Save coverage percentage for next step | |
| file_put_contents("coverage-summary.txt", $percentage); | |
| } else { | |
| echo "No coverage data found\n"; | |
| file_put_contents("coverage-summary.txt", "0"); | |
| } | |
| ' | |
| echo "Merged coverage summary saved" | |
| - name: Generate coverage summary | |
| id: coverage | |
| run: | | |
| if [ ! -f coverage-summary.txt ]; then | |
| echo "current_coverage=0" >> $GITHUB_OUTPUT | |
| echo "Current code coverage: 0%" | |
| exit 0 | |
| fi | |
| COVERAGE=$(cat coverage-summary.txt) | |
| echo "current_coverage=$COVERAGE" >> $GITHUB_OUTPUT | |
| echo "Current code coverage: $COVERAGE%" | |
| - name: Save current coverage | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| cp coverage-summary.txt /tmp/current-coverage.txt | |
| echo "Saved current coverage: $(cat coverage-summary.txt)%" | |
| - name: Comment PR with coverage | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const current = parseFloat('${{ steps.coverage.outputs.current_coverage }}'); | |
| const emoji = current >= 80 ? '🎉' : current >= 60 ? '📈' : current >= 40 ? '📊' : '📉'; | |
| const status = current >= 40 ? '✅' : '⚠️'; | |
| const comment = `## ${status} Code Coverage Report | |
| | Metric | Value | | |
| |--------|-------| | |
| | **Total Coverage** | **${current.toFixed(2)}%** ${emoji} | | |
| Coverage collected from **18 test groups** running in parallel: | |
| - activities, badges, admin, api, goals, updates, ui, utils, misc | |
| - suggested-tasks-providers (1-4) | |
| - suggested-tasks-data-collectors (1-3) | |
| ${current >= 40 ? '✅ Coverage meets minimum threshold' : '⚠️ Coverage below recommended 40% threshold'} | |
| _Tests are grouped to avoid memory/timeout issues. Each group runs independently with Xdebug coverage._ | |
| 🤖 Generated with [Claude Code](https://claude.com/claude-code) | |
| `; | |
| const {data: comments} = await github.rest.issues.listComments({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Code Coverage Report') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| comment_id: botComment.id, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: comment | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: comment | |
| }); | |
| } | |
| - name: Upload coverage summary | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-summary | |
| path: coverage-summary.txt | |
| retention-days: 30 |