DEV Community

Cover image for GitHub Code Coverage in Pull Requests: What Developers Should Set Up Now
Nimesh Kulkarni
Nimesh Kulkarni

Posted on

GitHub Code Coverage in Pull Requests: What Developers Should Set Up Now

GitHub just made code coverage visible inside pull requests through GitHub Code Quality, now in public preview.

That sounds like a small UI update, but it changes a common review problem: reviewers often approve code without knowing whether the new path is tested at all. If coverage is available directly in the PR, the conversation moves from vague “please add tests” comments to a clearer signal: what changed, what is covered, and what should we block before merge?

This post breaks down what shipped, why it matters, and how to wire it into a real GitHub Actions workflow.

What changed?

GitHub Code Quality can now show an aggregate code coverage percentage directly on pull requests.

Instead of sending reviewers to a separate coverage dashboard, your CI can upload a Cobertura XML report to GitHub, and GitHub displays the coverage context where the review already happens.

At a high level:

  1. Your CI runs tests.
  2. Your test tooling generates a Cobertura coverage report.
  3. GitHub Actions uploads that report using actions/upload-code-coverage.
  4. The pull request shows coverage information for reviewers.

GitHub says the feature is available for GitHub Team and GitHub Enterprise Cloud users during the preview period, and the preview is currently free.

Why this is useful in code review

Coverage is not the same thing as quality. A codebase can have high coverage and still have weak tests.

But coverage is still a useful review signal because it catches obvious gaps early:

  • new business logic with no tests
  • refactors that accidentally remove coverage
  • risky files that keep changing without test protection
  • PRs where reviewers need to ask better questions before merge

The win is not “coverage number go up.” The win is reviewers seeing test completeness without leaving the PR.

Minimal GitHub Actions setup

The new upload action expects a Cobertura XML file.

Here is a practical Python example using pytest-cov:

name: CI

on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    permissions:
      contents: read
      code-quality: write

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest pytest-cov
          pip install -r requirements.txt

      - name: Run tests with coverage
        run: |
          pytest --cov=. --cov-report=xml:cobertura.xml

      - name: Upload coverage to GitHub Code Quality
        uses: actions/upload-code-coverage@v1
        with:
          file: cobertura.xml
          language: Python
          label: code-coverage/pytest
Enter fullscreen mode Exit fullscreen mode

The important permission is:

permissions:
  contents: read
  code-quality: write
Enter fullscreen mode Exit fullscreen mode

Without code-quality: write, the workflow can run tests successfully but fail to upload the coverage report.

Node.js example

If your project is JavaScript or TypeScript, the idea is the same: generate Cobertura, then upload it.

For example, with Jest:

{
  "scripts": {
    "test:coverage": "jest --coverage --coverageReporters=cobertura"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then in GitHub Actions:

- name: Run tests with coverage
  run: npm run test:coverage

- name: Upload coverage to GitHub Code Quality
  uses: actions/upload-code-coverage@v1
  with:
    file: coverage/cobertura-coverage.xml
    language: TypeScript
    label: code-coverage/jest
Enter fullscreen mode Exit fullscreen mode

Adjust the language, label, and file path based on your stack.

A better pattern for larger teams

For production repos, I would avoid mixing “test execution” and “coverage upload” too tightly.

A cleaner pattern is:

  1. Run tests in the main CI job.
  2. Upload the coverage XML as a workflow artifact.
  3. Use a separate upload job with the narrow code-quality: write permission.

That keeps permissions scoped and makes debugging easier.

jobs:
  test:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/test-with-coverage.sh
      - uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: cobertura.xml

  upload-coverage:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      code-quality: write
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: coverage-report

      - uses: actions/upload-code-coverage@v1
        with:
          file: cobertura.xml
          language: Python
          label: code-coverage/ci
Enter fullscreen mode Exit fullscreen mode

This is especially useful if your organization is strict about GitHub token permissions.

What not to do

Do not turn coverage into a vanity metric.

A few bad patterns:

  • blocking every PR because coverage dropped by 0.1%
  • rewarding useless tests that only execute lines without assertions
  • treating generated files, migrations, and config as equally important as core logic
  • ignoring flaky tests because the coverage number looks good

A healthier rule is:

Coverage should guide review, not replace review.

Use it to ask better questions:

  • Is the risky path covered?
  • Are failure cases tested?
  • Did this PR reduce coverage in files that matter?
  • Are the tests meaningful or just line execution?

Practical checklist

If you want to try this today:

  • Confirm your repo has GitHub Code Quality enabled.
  • Generate Cobertura XML from your test runner.
  • Add code-quality: write to the upload job permissions.
  • Use actions/upload-code-coverage@v1.
  • Start by surfacing coverage in PRs before enforcing strict gates.
  • Decide which files should be excluded from coverage expectations.
  • Document what coverage means for your team.

Takeaway

GitHub putting coverage directly in pull requests is a nice step toward more useful code review.

Not because coverage is perfect, but because context matters. If reviewers can see test coverage while they are already reviewing the diff, teams can catch missing tests earlier and avoid yet another external dashboard.

Start simple: upload the report, observe the signal, and only then decide whether your team needs stricter rules.

References

Top comments (0)