Skip to content

Instantly share code, notes, and snippets.

@bradhowes
Created December 21, 2021 18:00
Show Gist options
  • Save bradhowes/0507a17b5d4db94fefc1b7190cb164fb to your computer and use it in GitHub Desktop.
Save bradhowes/0507a17b5d4db94fefc1b7190cb164fb to your computer and use it in GitHub Desktop.
Github Action for Swift Code Coverage
  1. Create a Github action for your SwiftPM project.
  2. Add a step to build: swift build
  3. Add a step to run tests: swift test --enable-code-coverage
  4. Fetch coverage value (see below)
  5. Write coverage value to gist and generate badge from it

For step #4, we need to do some sleuthing and digging around into artifacts created by the Swift toolchain. First, we need to find the location of the XCTest bundle that step #3 generated and save it in an environment variable:

XCTEST_PATH="$(find . -name '*.xctest')"

Next, we run llvm-cov to generate a report using the contents of the bundle and another file that contains the code coverage values:

xcrun llvm-cov report ${XCTEST_PATH}/Contents/MacOS/*PackageTests -instr-profile .build/debug/codecov/default.profdata -ignore-filename-regex='.build/|Tests/'

The above generates a report like so:

Filename                      Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DVV.swift                          42                 8    80.95%          26                 4    84.62%          58                 6    89.66%           0                 0         -
Dot.swift                           2                 0   100.00%           2                 0   100.00%           2                 0   100.00%           0                 0         -
DotVector.swift                    41                 1    97.56%          16                 1    93.75%          63                 1    98.41%           0                 0         -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                              85                 9    89.41%          44                 5    88.64%         123                 7    94.31%           0                 0         -

We are only interested in the last line, so we will pipe the above command into a tail -1 process, and we will use the Bash shell's set command to parse the line and get the 4th item that is the percentage. This is then saved for a future action step.

The whole step is for generating the coverage percentage value is this:

XCTEST_PATH="$(find . -name '*.xctest')"
set -- $(xcrun llvm-cov report ${XCTEST_PATH}/Contents/MacOS/*PackageTests -instr-profile .build/debug/codecov/default.profdata -ignore-filename-regex='.build/|Tests/' | tail -1)
echo "$4" > .build/debug/codecov/percentage.txt
echo "PERCENTAGE=$4" >> $GITHUB_ENV

Finally, with an appropriate Github GIST setup, we can generate a badge that shows the coverage value. The step below runs the dynamic-badges-action action that takes a Gist ID and filename, updates it with the value taken from the environment set in the previous stage, and builds a badge called "Coverage" with its value.

- name: Create Coverage Badge
  uses: schneegans/dynamic-badges-action@v1.1.0
  with:
    auth: ${{ secrets.GIST_UPDATE }}
    gistID: ad941184ed256708952a2057fc5d7bb4
    filename: swift-math-parser-coverage.json
    label: Coverage
    message: ${{ env.PERCENTAGE }}
    color: success
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment