brianhenryie/php-codecoverage-markdown

Generate markdown coverage reports from PHPUnit code coverage data for GitHub PR comments

Installs: 46

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/brianhenryie/php-codecoverage-markdown

0.1 2026-01-18 05:52 UTC

This package is auto-updated.

Last update: 2026-01-19 04:55:26 UTC


README

PHP 7.4

PHP Code Coverage Markdown Report Printer

Generate Markdown coverage reports from PHPUnit code coverage data, for GitHub PR comments.

PHPUnit

Features

  • 📊 Convert PHPUnit .cov coverage files to Markdown
  • 🔗 Link files to GitHub blob URLs
  • 📝 Filter reports to specific files
  • 🎨 Visual coverage bars using emojis (🟩🟧🟥⬜)

The Markdown report includes:

  • Total coverage summary
  • Per-file coverage details with:
    • Lines coverage percentage
    • Visual coverage bar
    • Methods coverage
    • Classes coverage
    • Clickable source/HTML report links, set with --base-url

Options

Primary input: coverage file in PHP format from phpunit/php-code-coverage:^9|^10|^11|^12, i.e. phpunit --coverage-php coveragephp.cov.

Option Short Description
--input-file -i Path to PHPUnit .cov coverage file (required)
--output-file -o Output file path (default: stdout)
--base-url -b Base URL for source file links (use %s as relative path placeholder)
--covered-files -c Comma-separated list of files to include (i.e. the files in the PR)

Limitation

GitHub Actions permissions limit new comments to users with write access to the repo. I.e. this works great for teams using private repos and works ok for PRs on public repos. There is a workaround at mshick/add-pr-comment-proxy which runs on Google Cloud.

Installation

composer require --dev brianhenryie/php-codecoverage-markdown:"^0.1|^1.0"

Usage

CLI

Generate a Markdown report from a PHPUnit coverage file:

php-codecoverage-markdown \
  --input-file tests/_reports/coveragephp.cov \
  --output-file coverage-report.md

With GitHub links:

php-codecoverage-markdown \
  --input-file tests/_reports/coveragephp.cov \
  --base-url "https://github.com/user/repo/blob/main/%s" \
  --output-file coverage-report.md

Filter to specific files:

php-codecoverage-markdown \
  --input-file tests/_reports/coveragephp.cov \
  --covered-files "src/MyClass.php,src/AnotherClass.php" \
  --output-file coverage-report.md

GitHub Actions

Use this to post coverage reports as PR comments:

name: PHP Tests with Code Coverage Report Comment

on:
  pull_request:
    types: [opened, synchronize]

env:
  COVERAGE_PHP_VERSION: '8.4'

jobs:
  php-tests:
    runs-on: ubuntu-latest

    permissions:
      pull-requests: write

    strategy:
      matrix:
        php: [ '8.2', '8.3', '8.4', '8.5' ]

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          coverage: ${{ matrix.php == env.COVERAGE_PHP_VERSION && 'xdebug' || 'none' }}

      - name: Install dependencies
        run: composer install

      - name: Run tests with coverage
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }} # We only need the coverage data once
        run: XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-php coveragephp.cov

      - name: Run tests without coverage
        if: ${{ matrix.php != env.COVERAGE_PHP_VERSION }}
        run: vendor/bin/phpunit

      - name: Get changed files
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        id: changed-files
        uses: tj-actions/changed-files@v47
        with:
          separator: ','
          files: '**/**.php'

      - name: Generate markdown report
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        run: |
          vendor/bin/php-codecoverage-markdown \
            --input-file coveragephp.cov \
            --covered-files=${{ steps.changed-files.outputs.all_changed_files }} \
            --base-url "https://github.com/${{ github.repository }}/blob/${{ github.event.pull_request.head.sha }}/%s" \
            --output-file coverage-report.md

      - name: Comment on PR
        uses: mshick/add-pr-comment@v2
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        with:
          message-id: coverage-report # Causes it to update the same PR comment each time.
          message-path: coverage-report.md
        continue-on-error: true # When a PR is opened by a non-member, there are no write permissions (and no access to secrets), so this step will always fail.

Programmatic

use BrianHenryIE\CodeCoverageMarkdown\MarkdownReport;
use SebastianBergmann\CodeCoverage\CodeCoverage;

/** @var CodeCoverage $coverage */
$coverage = include 'path/to/coveragephp.cov';

$report = new MarkdownReport();
$markdown = $report->process(
    coverage: $coverage,
    projectRoot: '/path/to/project/',
    baseUrl: 'https://github.com/user/repo/blob/main/%s',
    coveredFilesList: ['src/MyClass.php']
);

file_put_contents('coverage-report.md', $markdown);

Status

  • Planned breaking change (~0.2): default output should only be the table; documentation can show how easiest to add headers, other info, etc.
  • Ironically, this project's tests pass locally but fail in GitHub Actions! I'll tag 1.0 when I figure that out
  • This should be spun into its own GitHub Action so it is not a dependency in a project

See Also