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.created posts 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.

Create your first report →

Related