# ReportGenerator ReportGenerator is a powerful code coverage visualization tool that converts coverage reports generated by various testing frameworks (coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov, lcov) into human-readable reports in multiple formats. It supports .NET, Java, and NodeJS projects, providing detailed line-by-line coverage visualization, risk hotspot analysis, and historical trend charts to track coverage evolution over time. The tool is available as a NuGet package, .NET global tool, Azure DevOps extension, and GitHub Action. ReportGenerator supports merging multiple coverage files into a single unified report, making it ideal for large projects with multiple test suites. It offers extensive output formats including HTML (with multiple themes), XML, JSON, Markdown, Badges, and integration-specific formats for SonarQube, TeamCity, and other CI/CD systems. ## Command Line Interface The primary interface for ReportGenerator is its command line tool that accepts coverage reports and generates visualized output in the specified format. ```bash # Basic usage: Generate HTML report from coverage file reportgenerator -reports:coverage.xml -targetdir:coveragereport # Multiple input files with globbing support reportgenerator -reports:"target\*\*.xml" -targetdir:coveragereport # Multiple report types with custom title and version tag reportgenerator -reports:coverage.xml -targetdir:coveragereport -reporttypes:Html;Cobertura;Badges -title:MyProject -tag:v1.4.5 # With source directories for path resolution reportgenerator -reports:"coverage1.xml;coverage2.xml" -targetdir:report -sourcedirs:"C:\MyProject" # Filter assemblies and classes reportgenerator -reports:coverage.xml -targetdir:coveragereport -assemblyfilters:"+Included;-Excluded.*" -classfilters:"+MyNamespace.*;-*Tests" # Enable history tracking for trend charts reportgenerator -reports:coverage.xml -targetdir:coveragereport -historydir:coveragehistory # Use custom plugins reportgenerator -reports:coverage.xml -targetdir:coveragereport -plugins:CustomReports.dll ``` ## .NET Integration with Coverlet ReportGenerator integrates seamlessly with .NET projects using coverlet for code instrumentation and coverage collection. ```xml runtime; build; native; contentfiles; analyzers; buildtransitive all all runtime; build; native; contentfiles; analyzers ``` ```powershell # Execute tests with coverage collection dotnet test --collect:"XPlat Code Coverage" # Generate HTML report from collected coverage "%UserProfile%\.nuget\packages\reportgenerator\5.5.4\tools\net8.0\ReportGenerator.exe" -reports:*\TestResults\*\coverage.cobertura.xml -targetdir:coveragereport ``` ## .NET Global Tool Installation Install ReportGenerator as a global dotnet tool for easy command-line access across all projects. ```bash # Install globally dotnet tool install -g dotnet-reportgenerator-globaltool # Install to specific tool path dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools # Install as local tool (requires tool-manifest) dotnet new tool-manifest dotnet tool install dotnet-reportgenerator-globaltool # Usage after global installation reportgenerator -reports:coverage.xml -targetdir:coveragereport -reporttypes:Html;Cobertura # Usage with tool-path installation tools\reportgenerator.exe -reports:coverage.xml -targetdir:coveragereport # Usage as local tool dotnet reportgenerator -reports:coverage.xml -targetdir:coveragereport ``` ## MSBuild Task Integration Integrate ReportGenerator directly into your MSBuild process for automated report generation during builds. ```xml ``` ## .netconfig Configuration File Persist ReportGenerator settings in a .netconfig file for consistent configuration across team members and CI environments. ```gitconfig [ReportGenerator] reports = "coverage.xml" targetdir = "C:\\report" reporttypes = "Latex;HtmlSummary" assemblyfilters = "+Test;-Test" classfilters = "+Test2;-Test2" # Multi-valued options using singular entries [ReportGenerator] report = "coverage1.xml" report = "coverage2.xml" reporttype = "Html" reporttype = "Cobertura" assemblyfilter = "+MyApp.*" assemblyfilter = "-*.Tests" sourcedir = "src" sourcedir = "lib" ``` ```bash # Manage .netconfig via CLI dotnet config reportgenerator.reporttypes "Html;Cobertura" dotnet config --add reportgenerator.report coverage3.xml dotnet config --unset-all reportgenerator.assemblyfilter ``` ## GitHub Actions Integration Add ReportGenerator to GitHub Actions workflows for automated coverage reporting in pull requests and builds. ```yaml name: Build and Test with Coverage on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup .NET Core uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x dotnet-quality: 'ga' - name: Build and Test run: dotnet test --collect:"XPlat Code Coverage" - name: ReportGenerator uses: danielpalme/ReportGenerator-GitHub-Action@v5 with: reports: '**/coverage.cobertura.xml' targetdir: 'coveragereport' reporttypes: 'HtmlInline;Cobertura;MarkdownSummaryGithub' assemblyfilters: '+*;-xunit*' classfilters: '+*' verbosity: 'Info' title: 'Code Coverage Report' tag: '${{ github.run_number }}_${{ github.run_id }}' - name: Upload coverage report uses: actions/upload-artifact@v4 with: name: CoverageReports path: coveragereport ``` ## GitHub Actions with Coverage History Track coverage trends over time by persisting history files as artifacts between builds. ```yaml name: Coverage with History on: [push] jobs: coverage: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x - name: Build and Test run: dotnet test --collect:"XPlat Code Coverage" - name: Restore coverage history uses: dawidd6/action-download-artifact@v3 with: name: CoverageHistory path: CoverageHistory continue-on-error: true - name: ReportGenerator uses: danielpalme/ReportGenerator-GitHub-Action@5 with: reports: '*Test*/TestResults/*/coverage.cobertura.xml' targetdir: 'CoverageReports' historydir: 'CoverageHistory' reporttypes: 'HtmlInline;Cobertura;SvgChart' - name: Upload coverage report uses: actions/upload-artifact@v4 with: name: CoverageReports path: CoverageReports - name: Upload coverage history uses: actions/upload-artifact@v4 with: name: CoverageHistory path: CoverageHistory ``` ## Azure DevOps Pipeline Integration Configure ReportGenerator in Azure DevOps YAML pipelines with built-in code coverage publishing. ```yaml trigger: - main pool: vmImage: 'ubuntu-latest' variables: disable.coverage.autogenerate: 'true' steps: - task: DotNetCoreCLI@2 displayName: 'Build and Test' inputs: command: 'test' arguments: '--collect:"XPlat Code Coverage"' - task: reportgenerator@5 displayName: 'Generate Coverage Report' inputs: reports: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml' targetdir: '$(Build.SourcesDirectory)/coveragereport' reporttypes: 'HtmlInline_AzurePipelines;Cobertura;Badges' assemblyfilters: '-xunit*;-*Tests' publishCodeCoverageResults: true title: 'Code Coverage - $(Build.BuildNumber)' tag: '$(Build.BuildNumber)' - publish: $(Build.SourcesDirectory)/coveragereport artifact: CoverageReports displayName: 'Publish Coverage Artifact' ``` ## Azure DevOps with History Storage Store coverage history in Azure Artifacts Universal Packages for long-term trend tracking. ```yaml variables: disable.coverage.autogenerate: 'true' codecoveragehistory.directory: '$(Build.ArtifactStagingDirectory)\history' codecoveragehistory.feedName: '$(Build.Repository.Name)-$(Build.SourceBranchName)' steps: - task: UniversalPackages@0 displayName: 'Download Coverage History' continueOnError: true inputs: command: 'download' downloadDirectory: '$(codecoveragehistory.directory)' feedsToUse: 'internal' vstsFeed: 'YOUR_FEED_ID' vstsFeedPackage: '$(codecoveragehistory.feedName)' vstsPackageVersion: '0.*' - task: reportgenerator@5 displayName: 'Create Coverage Report' inputs: reports: '$(Build.SourcesDirectory)\**\coverage.cobertura.xml' targetdir: '$(Build.SourcesDirectory)\CodeCoverage' historydir: '$(codecoveragehistory.directory)' reporttypes: 'HtmlInline_AzurePipelines;Cobertura;HtmlChart' title: 'Coverage for $(Build.Repository.Name)' publishCodeCoverageResults: true - task: UniversalPackages@0 displayName: 'Publish Coverage History' inputs: command: 'publish' publishDirectory: '$(codecoveragehistory.directory)' feedsToUsePublish: 'internal' vstsFeedPublish: 'YOUR_FEED_ID' vstsFeedPackagePublish: '$(codecoveragehistory.feedName)' versionOption: 'patch' ``` ## GitLab CI Integration Configure ReportGenerator in GitLab CI pipelines with coverage badge support. ```yaml stages: - build - test build_job: stage: build script: - 'dotnet restore --packages .nuget' - 'dotnet publish -c Release .\MyProject\MyProject.csproj' test_job: stage: test script: - 'mkdir coveragereports' - 'dotnet test -c Release --collect:"XPlat Code Coverage"' - '.\.nuget\reportgenerator\5.5.4\tools\net8.0\ReportGenerator.exe -reports:MyProject.Test\TestResults\*\coverage.cobertura.xml -targetdir:coveragereports "-reporttypes:Html;TeamCitySummary" -verbosity:Info -historydir:coveragehistory' # Regex to extract coverage for GitLab badge coverage: '/##teamcity\[buildStatisticValue key=''CodeCoverageS'' value=''(\d+\.?\d*)''\]/' artifacts: paths: - '.\coveragereports' dependencies: - build_job ``` ## Java/JaCoCo Integration Generate ReportGenerator reports from JaCoCo coverage data in Maven projects. ```xml org.jacoco jacoco-maven-plugin 0.8.14 prepare-agent report prepare-package report ``` ```powershell # Run tests and generate JaCoCo report mvn test jacoco:report # Install ReportGenerator and generate HTML report dotnet tool update dotnet-reportgenerator-globaltool --tool-path tools --version 5.5.4 tools\reportgenerator -reports:target\site\jacoco\jacoco.xml -targetdir:coveragereport -sourcedirs:src\main\java -reporttypes:Html;Cobertura ``` ## NodeJS/Istanbul Integration Generate coverage reports from Istanbul/nyc coverage data for JavaScript projects. ```bash # Install nyc (Istanbul CLI) npm i nyc --save-dev # Run tests with coverage collection nyc --reporter=cobertura mocha # Install and run ReportGenerator dotnet tool update dotnet-reportgenerator-globaltool --tool-path tools --version 5.5.4 tools/reportgenerator -reports:coverage/cobertura-coverage.xml -targetdir:coveragereport -reporttypes:Html;MarkdownSummary ``` ## Output Format Types ReportGenerator supports numerous output formats for different use cases and integrations. ```bash # HTML formats (interactive reports) reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Html reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Html_Dark reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Html_Light reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Html_BlueRed reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:HtmlInline reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:HtmlInline_AzurePipelines reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:HtmlSummary reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:MHtml # XML formats (machine-readable) reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Xml reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:XmlSummary reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Cobertura reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Clover reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:OpenCover # JSON formats reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:JsonSummary reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:CodeClimate # Markdown formats reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Markdown reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:MarkdownSummary reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:MarkdownSummaryGithub reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:MarkdownDeltaSummary # CI/CD specific formats reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:SonarQube reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:TeamCitySummary reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:lcov # Visual formats reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:Badges reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:SvgChart reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:HtmlChart # Multiple formats in single run reportgenerator -reports:coverage.xml -targetdir:report -reporttypes:"Html;Cobertura;Badges;MarkdownSummaryGithub" ``` ## Coverage Thresholds Configuration Configure minimum coverage thresholds to fail builds when coverage drops below acceptable levels. ```bash # Fail if line coverage is below 80% reportgenerator -reports:coverage.xml -targetdir:report "minimumCoverageThresholds:lineCoverage=80" # Fail if branch coverage is below 70% reportgenerator -reports:coverage.xml -targetdir:report "minimumCoverageThresholds:branchCoverage=70" # Fail if method coverage is below 90% reportgenerator -reports:coverage.xml -targetdir:report "minimumCoverageThresholds:methodCoverage=90" # Multiple thresholds combined reportgenerator -reports:coverage.xml -targetdir:report \ "minimumCoverageThresholds:lineCoverage=80" \ "minimumCoverageThresholds:branchCoverage=70" \ "minimumCoverageThresholds:methodCoverage=85" ``` ## Risk Hotspots Configuration Configure thresholds for identifying and enforcing limits on code complexity metrics. ```bash # Custom thresholds for risk hotspot identification reportgenerator -reports:coverage.xml -targetdir:report \ "riskHotspotsAnalysisThresholds:metricThresholdForCyclomaticComplexity=15" \ "riskHotspotsAnalysisThresholds:metricThresholdForCrapScore=30" \ "riskHotspotsAnalysisThresholds:metricThresholdForNPathComplexity=200" # Fail build if complexity exceeds maximum reportgenerator -reports:coverage.xml -targetdir:report \ "riskHotspotsAnalysisThresholds:maximumThresholdForCyclomaticComplexity=50" \ "riskHotspotsAnalysisThresholds:maximumThresholdForCrapScore=100" # Disable risk hotspots analysis entirely reportgenerator -reports:coverage.xml -targetdir:report "settings:disableRiskHotspots=true" ``` ## Advanced Settings Fine-tune ReportGenerator behavior with advanced configuration options for performance and output customization. ```bash # Performance tuning: parallel processing reportgenerator -reports:coverage.xml -targetdir:report \ "settings:numberOfReportsParsedInParallel=4" \ "settings:numberOfReportsMergedInParallel=4" # Limit history files for faster processing reportgenerator -reports:coverage.xml -targetdir:report \ "settings:maximumNumberOfHistoricCoverageFiles=50" # Custom headers for remote file access (e.g., private repos) reportgenerator -reports:coverage.xml -targetdir:report \ "settings:customHeadersForRemoteFiles=Authorization=Bearer YOUR_TOKEN" # Create subdirectories for each report type reportgenerator -reports:coverage.xml -targetdir:report \ -reporttypes:"Html;Cobertura;Badges" \ "settings:createSubdirectoryForAllReportTypes=true" # Set decimal places for coverage percentages reportgenerator -reports:coverage.xml -targetdir:report \ "settings:maximumDecimalPlacesForCoverageQuotas=2" # Default assembly name for gcov/lcov reports reportgenerator -reports:coverage.xml -targetdir:report \ "settings:defaultAssemblyName=MyApplication" ``` ## Custom Report Plugin (IReportBuilder) Create custom output formats by implementing the IReportBuilder interface and loading as a plugin. ```csharp // CustomCsvReportBuilder.cs - Create a .NET Standard 2.0 library using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using Palmmedia.ReportGenerator.Core.Parser.Analysis; using Palmmedia.ReportGenerator.Core.Reporting; namespace MyCompany.CustomReportTypes { public class CsvSummaryReportBuilder : IReportBuilder { // Report type name - use with -reporttypes:CsvSummary public string ReportType => "CsvSummary"; // ReportGenerator injects this context public IReportContext ReportContext { get; set; } // Called for each class in coverage data public void CreateClassReport(Class @class, IEnumerable fileAnalyses) { // Implement per-class reporting if needed } // Called once with aggregated results public void CreateSummaryReport(SummaryResult summaryResult) { string targetPath = Path.Combine( this.ReportContext.ReportConfiguration.TargetDirectory, "Summary.csv"); using (var writer = new StreamWriter( new FileStream(targetPath, FileMode.Create), Encoding.UTF8)) { writer.WriteLine("Assembly,Coverage"); foreach (var assembly in summaryResult.Assemblies) { var coverage = assembly.CoverageQuota.HasValue ? assembly.CoverageQuota.Value.ToString("f1", CultureInfo.InvariantCulture) + "%" : "N/A"; writer.WriteLine($"{assembly.Name},{coverage}"); foreach (var @class in assembly.Classes) { var classCoverage = @class.CoverageQuota.HasValue ? @class.CoverageQuota.Value.ToString("f1", CultureInfo.InvariantCulture) + "%" : "N/A"; writer.WriteLine($" {@class.Name},{classCoverage}"); } } } } } } ``` ```bash # Build the plugin and use it dotnet build CustomReports.csproj -c Release reportgenerator -reports:coverage.xml -targetdir:report -plugins:CustomReports.dll -reporttypes:CsvSummary ``` ## Custom History Storage Plugin (IHistoryStorage) Implement custom storage for coverage history (e.g., cloud storage) by implementing IHistoryStorage. ```csharp // AmazonS3HistoryStorage.cs - Store history in S3 using System.Collections.Generic; using System.IO; using Amazon.S3; using Amazon.S3.Model; using Amazon.S3.Transfer; using Palmmedia.ReportGenerator.Core.Reporting.History; namespace MyCompany.CustomHistoryStorage { public class AmazonS3HistoryStorage : IHistoryStorage { private readonly string _bucketName; private readonly AmazonS3Client _client; public AmazonS3HistoryStorage() { // Read from environment or command line arguments _bucketName = Environment.GetEnvironmentVariable("S3_BUCKET_NAME"); var accessKey = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID"); var secretKey = Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY"); _client = new AmazonS3Client(accessKey, secretKey, Amazon.RegionEndpoint.USEast1); } public IEnumerable GetHistoryFilePaths() { var request = new ListObjectsV2Request { BucketName = _bucketName, MaxKeys = 200 }; ListObjectsV2Response response; do { response = _client.ListObjectsV2Async(request).Result; foreach (S3Object entry in response.S3Objects) { yield return entry.Key; } request.ContinuationToken = response.NextContinuationToken; } while (response.IsTruncated); } public Stream LoadFile(string filePath) { var transferUtility = new TransferUtility(_client); return transferUtility.OpenStream(_bucketName, filePath); } public void SaveFile(Stream stream, string fileName) { var transferUtility = new TransferUtility(_client); transferUtility.Upload(stream, _bucketName, fileName); } } } ``` ```bash # Use custom history storage plugin export S3_BUCKET_NAME=my-coverage-history export AWS_ACCESS_KEY_ID=your_key export AWS_SECRET_ACCESS_KEY=your_secret reportgenerator -reports:coverage.xml -targetdir:report -plugins:S3HistoryStorage.dll -reporttypes:Html;HtmlChart ``` ## Filtering Coverage Data Apply filters to include or exclude specific assemblies, classes, and files from coverage reports. ```bash # Include only specific assemblies (+ prefix) reportgenerator -reports:coverage.xml -targetdir:report -assemblyfilters:"+MyApp.Core;+MyApp.Services" # Exclude test assemblies (- prefix) reportgenerator -reports:coverage.xml -targetdir:report -assemblyfilters:"+*;-*Tests;-*Test;-xunit*" # Wildcard patterns for assemblies reportgenerator -reports:coverage.xml -targetdir:report -assemblyfilters:"+MyCompany.*;-*.Tests.*" # Class filters reportgenerator -reports:coverage.xml -targetdir:report -classfilters:"+MyApp.Domain.*;-*Generated*" # File filters reportgenerator -reports:coverage.xml -targetdir:report -filefilters:"+*.cs;-*Designer.cs;-*.g.cs" # Risk hotspot filters (separate from main filters) reportgenerator -reports:coverage.xml -targetdir:report \ -riskhotspotassemblyfilters:"+MyApp.Core" \ -riskhotspotclassfilters:"-*Controller" # Combined filtering reportgenerator -reports:coverage.xml -targetdir:report \ -assemblyfilters:"+MyApp.*;-*Tests" \ -classfilters:"+*;-*Generated*" \ -filefilters:"+*;-*.Designer.cs" ``` ## Programmatic API Usage Use ReportGenerator.Core NuGet package to invoke report generation from within your .NET application. ```csharp // Install: dotnet add package ReportGenerator.Core using Palmmedia.ReportGenerator.Core; // Basic programmatic usage var reportGenerator = new Generator(); var reportConfiguration = new ReportConfiguration( reportFiles: new[] { "coverage.cobertura.xml" }, targetDirectory: "coveragereport", sourceDirectories: new[] { "src" }, historyDirectory: "history", reportTypes: new[] { "Html", "Cobertura", "Badges" }, plugins: Array.Empty(), assemblyFilters: new[] { "+*", "-*Tests" }, classFilters: new[] { "+*" }, fileFilters: new[] { "+*" }, verbosityLevel: "Info", title: "My Coverage Report", tag: "v1.0.0" ); bool success = reportGenerator.GenerateReport(reportConfiguration); if (!success) { Console.WriteLine("Report generation failed"); Environment.Exit(1); } ``` ## Summary ReportGenerator serves as the industry-standard tool for code coverage visualization in .NET ecosystems and beyond. Its primary use cases include generating human-readable HTML reports from machine-generated coverage data, tracking coverage trends over time with history charts, enforcing minimum coverage thresholds in CI/CD pipelines, and producing CI-specific outputs for platforms like Azure DevOps, GitHub Actions, GitLab, TeamCity, and SonarQube. The tool excels at merging multiple coverage files from different test projects into unified reports, making it ideal for microservice architectures and monorepos. Integration patterns typically involve adding ReportGenerator to the test phase of build pipelines, either as a dotnet global tool, NuGet package reference, or platform-specific extension (Azure DevOps, GitHub Actions). For advanced scenarios, the plugin architecture allows custom output formats via IReportBuilder and custom history storage via IHistoryStorage, enabling integration with cloud storage services or proprietary reporting systems. The extensive filtering capabilities allow teams to focus on relevant coverage metrics while excluding generated code, test frameworks, and third-party dependencies from reports.