Share a CircleCI HTML report
Credit where it's due: CircleCI's Artifacts tab actually renders HTML. Add
store_artifacts, click the file, see the report. That's more than GitHub
Actions or GitLab.com will do for you.
The problems are all around it:
- The URL changes every job. There is no "the coverage report" link — only "the coverage report from job 48213", which is useless in a bookmark, a runbook, or a Slack message someone reads next Tuesday.
- 30-day retention. The report from the release you're investigating in next quarter's review is gone.
- Login required. The reviewer must have CircleCI access to the project. For an engineer that's fine. For the PM, the security reviewer, the customer or the auditor, it's a non-starter — and it's exactly why reports get screenshotted.
- Nowhere to respond. The artifact is a dead end. Every question about it happens somewhere else, detached from the thing it's about.
Publish it from the job instead
Store a scoped token (reports:write only) as a project
environment variable, create the report once, and PATCH it every run:
version: 2.1
jobs:
test:
docker:
- image: cimg/python:3.12
steps:
- checkout
- run: pip install -r requirements.txt
- run:
name: Run tests with coverage
command: pytest --cov --cov-report=html
- store_artifacts:
path: htmlcov
- run:
name: Publish report to Comma
when: always
command: |
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$COMMA_REPORT_ID" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html htmlcov/index.html \
--arg title "Coverage — $CIRCLE_SHA1" \
'{title: $title, html: $html}')"
echo "Report → https://commareports.com/p/$COMMA_REPORT_ID"
when: always is the important flag — the red runs are the ones worth
reading, and the default only publishes on green.
Note that store_artifacts stays. Keeping the artifact for engineers who are
already in CircleCI costs nothing; the published report is for everyone else.
What the published copy adds
- One URL, forever. Each job appends a revision at the same address, and any two revisions can be diffed — "what changed since the last green build" becomes a question with an answer.
- Readers without a CircleCI seat. Visibility is private, team, domain-gated, or link, independent of your CI provider's ACL.
- Comments anchored to the content. A reviewer highlights the line that regressed and pins a thread to it, and that thread survives every subsequent run — see commenting on HTML.
- No retention clock. Revisions stay.
- Announcements. A webhook on
revision.createdposts the new revision to Slack or Discord.
Limits
- HTML body: 5 MB. Screenshots, videos and archives go in as assets at 25 MB per file, 250 MB per report.
- Scripts are stripped on write, so a JavaScript-application report (Allure, Playwright's default reporter) should be published as a static digest with the archive attached — see sharing an Allure report.
- Rate limit: 60 requests/minute per token. One publish per build is nowhere near it.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.
Related
- Publish from CI — the general pipeline pattern
- GitHub Actions HTML reports
- GitLab CI HTML reports
- Jenkins HTML reports