Post

Publishing Coverage Reports with ReportGenerator to GitHub Pages

As a big fan of the ReportGenerator .NET tool, I’ve been relying on it to visualize code coverage in my .NET projects. It’s flexible and supports a variety of output formats such as HTML, Markdown, and even badges.

When I was using Azure DevOps, integrating ReportGenerator into my CI pipelines was simple, thanks to the official extension that displays reports in a dedicated tab within the job summary UI.

However, once I moved my CI pipelines to GitHub Actions, I noticed a gap. GitHub doesn’t provide native UI support for browsing rich coverage reports. I wanted a simple, automated solution that:

  • Generates interactive reports.
  • Publishes them with every push to main.
  • Gives me a badge in my README.md that links directly to the latest report.

That’s when GitHub Pages came to the rescue. GitHub Pages is a free static site hosting feature available for public repositories. By leveraging a dedicated branch (e.g., coverage-reports) and GitHub Actions, we can automatically publish the HTML output from ReportGenerator.

GitHub Actions Workflow

You can check the original content here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
name: Full Build

on: 
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4

    - name: Setup dotnet
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: 9.x

    - name: Build
      run: dotnet build --configuration Release

    - name: Test
      run: dotnet test --configuration Release --no-build --no-restore --collect:"XPlat Code Coverage"

    - name: ReportGenerator
      uses: danielpalme/[email protected]
      with:
        reports: tests/**/coverage.cobertura.xml
        targetdir: ${{ runner.temp }}/coveragereport
        reporttypes: 'Html;Badges;MarkdownSummaryGithub'
        assemblyfilters: -*Tests*

    - name: Publish coverage report in build summary
      run: cat '${{ runner.temp }}'/coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY
      shell: bash

    - name: Create coverage-reports branch and push content
      run: |
        git fetch
        git checkout coverage-reports || git checkout --orphan coverage-reports
        git reset --hard
        git clean -fd
        cp -rp '${{ runner.temp }}'/coveragereport/* ./
        echo "YOUR_CUSTOM_DOMAIN" > CNAME
        git config user.name github-actions
        git config user.email [email protected]
        git add .
        git commit -m "Update coverage reports [skip ci]" || echo "No changes to commit"
        git push origin coverage-reports --force
      shell: bash

What This Does

  • Runs your tests with coverage collection enabled (XPlat Code Coverage).
  • Uses ReportGenerator to produce:
    • Rich HTML reports.
    • Markdown summaries published to the job’s summary page.
    • Badges that you can embed in your README.md.
  • Publishes the output to a dedicated branch (coverage-reports) which can be served via GitHub Pages.
  • Uses a custom domain (optional) if you’re using a GitHub Pages custom domain. Exclude the following line if you don’t use a custom domain echo "YOUR_CUSTOM_DOMAIN" > CNAME.

Add the Badge to Your README

Once the report is published to GitHub Pages, you can link to the badge generated by ReportGenerator. If you click on the badge you’re redirected to the coverage report.

1
[![Coverage](https://<your-username>.github.io/<repo-name>/badge_linecoverage.svg)](https://<your-username>.github.io/<repo-name>)

Final Thoughts

This was one feature I truly missed after moving away from Azure DevOps. Thankfully, with a bit of GitHub Actions magic, I was able to recreate a similar (and fully automated) experience.

This setup has been working great across my projects. If you’re curious to see it in action, check out the QuerySpecification repository.

I hope you found this article useful. Happy coding!

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.