Generating coverage reports & badges for SwiftPM apps

Remko Tronçon ·

The age plugin for Apple’s Secure Enclave is a small, platform-independent Swift CLI app, built using the Swift Package Manager. Because it does not use Xcode for building, you can’t use the Xcode IDE for collecting and browsing test coverage of your source files. I therefore wrote a small (self-contained, dependencyless, cross-platform) Swift script to transform SwiftPM’s raw coverage data into annotated source code, together with an SVG badge to put on your project page.

age-plugin-se Coverage

age-plugin-se Coverage Report

Running the script

To create a coverage report, first run the unit tests with coverage tracking enabled:

$ swift test --enable-code-coverage

Building for debugging...
[25/25] Linking AgeSecureEnclavePluginPackageTests
Build complete! (23.38s)
Test Suite 'All tests' started at 2024-04-20 21:51:18.947.
Test Suite 'All tests' passed at 2024-04-20 21:51:19.017.
	 Executed 79 tests, with 0 failures (0 unexpected) in 0.064 (0.069) seconds

Then, you can run the script on the coverage data, and output the HTML and SVG:

$ ./Scripts/ProcessCoverage.swift \
    `swift test --show-codecov-path` .build/coverage.json \
    .build/coverage.html .build/coverage.svg

Code coverage (lines):
  Sources/Base64.swift          30/30 (100.0%)
  Sources/Bech32.swift        160/175  (91.4%)
  Sources/CLI.swift            59/133  (44.4%)
  Sources/Crypto.swift           4/15  (26.7%)
  Sources/Plugin.swift        378/381  (99.2%)
  Sources/Stream.swift            0/8   (0.0%)
  TOTAL                       631/742  (85.0%)

A summary is printed as well, which is useful for quick testing or for logging in CI.

The layout of the generated HTML is heavily inspired by Go’s go tool cover -html output.

Publishing the coverage report on GitHub

When you use GitHub, you can use a GitHub action to publish the resulting HTML (and badge) to GitHub Pages. For example, the following workflow steps publish the HTML to https://<username><project>/ci/coverage.html, and the SVG badge to https://<username><project>/ci/coverage.svg:

  - name: Copy coverage report & badge
    run: |
      mkdir -p .build/site/ci
      cp .build/coverage.svg .build/coverage.html .build/site/ci      
    shell: bash
  - name: Upload pages
    uses: actions/upload-pages-artifact@v1
      path: .build/site
  - name: Deploy to GitHub Pages
    id: deployment
    uses: actions/deploy-pages@v1

  name: github-pages
  url: ${{ steps.deployment.outputs.page_url }}

You can then include an inline badge image with a link to the coverage report in your for your project page (as seen here):



Besides adding an Xcode project, you can also use a combination of llvm-cov export and LCOV on the coverage data to get source code reports. However, I had problems getting llvm-cov and LCOV installed and working on my machine (I didn’t even try on GitHub), and I also prefer to avoid unnecessary dependencies when I can.