coverage.py's HTML report, as a link on every PR
coverage html turns your test run into a browsable site with per-line hit highlighting. Instead of letting it rot in an artifacts zip, publish it — reviewers open a link and see exactly which lines your diff missed.
The artifact dead-end
The console summary tells you coverage dropped 2%. The HTML report tells you which lines. Guess which one ends up zipped in the artifacts tab where nobody opens it.
Reviewers deserve the annotated source — yellow partial branches, red misses — one click from the PR, not a download-and-extract ritual.
Two lines to a live link
Generate the report like you already do, then hand the folder to the action:
Generate the report
coverage run -m pytest && coverage html.github/workflows/ci.yml
- uses: bitgate/ship-page-action@v1
if: always()
with:
path: htmlcov/Omit path entirely and the action auto-detects htmlcov/ on its own. The URL lands in the job summary — add comment: true and it lands on the pull request too.
What you get
- Per-file annotated source renders exactly as coverage.py wrote it — served from the root of its own subdomain
- Works with pytest-cov too: --cov-report=html produces the same htmlcov/ layout
- Omit path entirely — the action auto-detects htmlcov/
Questions
Does it work with pytest-cov?
Yes — pytest --cov=. --cov-report=html writes htmlcov/, the exact layout the action looks for.
Can I keep one stable coverage URL per branch?
Yes: name: cov-${{ github.ref_name }} plus an sp_ API key redeploys the same URL on every push to that branch.
Is my source code exposed?
The report contains annotated source, so treat the URL like a secret: slugs are unguessable and there's no listing. For sensitive repos, use expiry — anonymous drops self-destruct after 7 days.
Try it on your next run
Anonymous deploys need no account and no key — paste the step, get a link. When you want stable URLs that redeploy in place, an API key and a name are all it takes.