-
Notifications
You must be signed in to change notification settings - Fork 0
Create GitHub Actions Workflows for Publishing Code Coverage Reports
Important
All of the files in this section should be created in the main
branch.
Note
My project is using Vitest for our tests, but most testing frameworks use Istanbul for reporting code coverage. If you are not using Istanbul, you will need to adjust these instructions to work for your report.
In a branch from main, open your test configurations. Set the reporter
to use at least the html
and json-summary
reporters. Specify the sub-directory for the html
report because we need all of those files contained separately from the other reports. Also, specify the thresholds
that you want for your coverage. You can set whatever you want for your project, these are just what we are using at the moment.
Note
The coverage thresholds set here should match your coverage values in the _config.yml
file on the gh-pages
branch.
import { configDefaults, defineConfig } from "vitest/config";
import { join } from "path";
export default defineConfig({
test: {
globals: true,
include: ["**/*.test.ts?(x)"],
coverage: {
provider: "istanbul",
reportsDirectory: join(__dirname, "coverage"),
reporter: [
["html", { subdir: "html-report" }], // required for this setup, must be nested within its own folder to avoid getting confused with the other reports
["json-summary"], // required for this setup
["text"], // OPTIONAL, you can use any additional reports that you like
],
thresholds: {
lines: 90,
branches: 90,
functions: 90,
statements: 90,
},
reportOnFailure: true,
exclude: [
...configDefaults.exclude,
".github/**",
"node_modules/**",
"playwright-reports/**",
"test-results/**",
"tests/**",
".gitignore",
"package.json",
"playwright.config.ts",
"pnpm-lock.yaml",
"README.md",
"vitest.config.ts",
],
},
},
});
Create .github/workflows/code-coverage-report.yml
that will run the tests with the coverage flag, upload the artifacts for the html
and json-summary
reports, then call the publish workflow.
name: Code Coverage Report
on:
push:
branches:
- main # run this whenever someone merged into main
schedule:
- cron: "30 01 * * *" # run this every morning at 1:30
workflow_dispatch: # allow manual triggering workflow
# ensures that currently running Code Coverage Report workflow is canceled if another job starts
concurrency:
group: ${{ github.workflow }}-main
cancel-in-progress: true
# this action needs the same permissions as the Push to GitHub Pages action because it is calling it
permissions:
actions: read
contents: write
jobs:
coverage-report:
runs-on: ubuntu-latest
env:
JSON_ARTIFACT_ID: json-main-coverage-report
HTML_ARTIFACT_ID: html-main-coverage-report
outputs:
json_artifact_id: ${{ env.JSON_ARTIFACT_ID }}
html_artifact_id: ${{ env.HTML_ARTIFACT_ID }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: main
#### this is our set up for installing and running the tests, update this with your set up and test run ####
- uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
- name: Run Tests
continue-on-error: true
run: pnpm exec vitest --coverage
#### end set up and test run ####
- name: Upload Coverage Summary
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
id: upload-json
with:
name: ${{ env.JSON_ARTIFACT_ID }}
# path should point to the location of your json coverage report
path: coverage/coverage-summary.json
overwrite: true
retention-days: 90
- name: Upload Coverage Report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
id: upload-html
with:
name: ${{ env.HTML_ARTIFACT_ID }}
# path should point to the location of your html coverage report
path: coverage/html-report/*
overwrite: true
retention-days: 90
publish:
needs: [coverage-report]
# call the push-to-gh-pages workflow to add the artifacts to gh-pages
uses: ./.github/workflows/push-to-gh-pages.yml
with:
FILE_1_ARTIFACT_ID: ${{ needs.coverage-report.outputs.json_artifact_id }}
FILE_1_DEPLOY_TO: _data/coverage/
FILE_2_ARTIFACT_ID: ${{ needs.coverage-report.outputs.html_artifact_id }}
FILE_2_DEPLOY_TO: coverage/
COMMIT_MSG: update code coverage report for main
URL_PATH: coverage/
secrets: inherit # allow called workflow to use GitHub secrets
Create .github/workflows/pr-coverage-annotation.yml
that will run on PRs to main
. For this setup, we are not reporting coverage for each branch. However, you can add the coverage report to the PR itself. This workflow also refers to the main
coverage report to show whether the coverage is going up or down in the PR.
name: PR Coverage Annotation
on:
pull_request:
branches:
- main
# ensures that currently running PR Coverage Annotation workflow is canceled if another one starts
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
permissions:
actions: read
contents: write
pull-requests: write
jobs:
coverage-report:
runs-on: ubuntu-latest
outputs:
actualResult: ${{ steps.test.conclusion }}
steps:
- uses: actions/checkout@v4
#### this is our set up for installing and running the tests, update this with your set up and test run ####
- uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install
- name: Run Tests
id: test
continue-on-error: true
run: pnpm exec vitest --coverage
#### end set up and test run ####
- name: Get run ID of Code Coverage Report workflow
# gets the run id of the last time Code Coverage Report ran so that it can be used to download that artifact
id: get-run-id
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
WF_NAME="Code Coverage Report"
RUN_ID=`gh run list --workflow "${WF_NAME}" --json databaseId --jq .[0].databaseId`
echo "Detected latest run id of ${RUN_ID} for workflow ${WF_NAME}"
echo "run-id=${RUN_ID}" >> "$GITHUB_OUTPUT"
- uses: actions/download-artifact@v4
if: steps.get-run-id.conclusion == 'success'
# if we were able to get the run id, download that json summary report using the run id
id: get-main-coverage
continue-on-error: true
with:
name: json-main-coverage-report
path: main-coverage
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ steps.get-run-id.outputs.run-id }}
- name: Report Coverage (compared with Main)
if: ${{ steps.get-run-id.conclusion == 'success' && steps.get-main-coverage.conclusion == 'success' }}
# if we were able to get the run id and download the main json summary report, then compare it to the current json summary report and add that to the PR
uses: davelosert/vitest-coverage-report-action@v2
with:
json-summary-compare-path: main-coverage/coverage-summary.json
file-coverage-mode: all
- name: Report Coverage (only PR)
if: ${{ failure() }}
# if we were not able to get the run id or download the main json summary report, then just add the current json summary report to the PR
uses: davelosert/vitest-coverage-report-action@v2
with:
file-coverage-mode: all