Skip to content

CoverageTracker/coverage-tracker

Repository files navigation

coverage-tracker

coverage (backend) badge coverage (frontend) badge License Scan

A self-hosted dashboard that tracks code coverage, cyclomatic complexity, and code duplication across your GitHub repositories — with trend charts, per-PR diff checks, and README badges.

Runs entirely on your own Cloudflare account (Worker + D1). Your data stays in your own database. No SaaS, no subscriptions, no third-party access to your metrics.

Catppuccin theme
Catppuccin
Gruvbox theme
Gruvbox
Nord theme
Nord
Solarized theme
Solarized
Dracula theme
Dracula
Tokyo Night theme
Tokyo Night

Deploy to Cloudflare

Note

The button deploys the Worker and provisions the D1 database automatically. You still need to complete the GitHub App, Cloudflare Zero Trust, and secrets setup described in docs/INSTALLATION.md.


How it works

  1. Install the GitHub App on the repos you want to track. The Worker registers them automatically via webhook.
  2. Add a workflow step to your CI that runs the reporting Action after your test suite. You run your tests and coverage tools; the Action reads the report file they produce (LCOV, Cobertura, JaCoCo, or the Go coverage profile — auto-detected) and pushes the numbers to the Worker using a GitHub Actions OIDC token — no static secrets.
  3. View trends in the dashboard (served as static assets by the Worker), protected by Cloudflare Access so only you can see it.
  4. Optionally embed a badge in your README.
┌─────────────────────────────────────────────────────────┐
│  Your CI (GitHub Actions)                               │
│                                                         │
│  run tests → write report → Action reads it → POST      │
│  /api/ci/coverage   (OIDC token, no static secret)      │
└───────────────────────────┬─────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────┐
│  Cloudflare Worker  (coverage-tracker.yourdomain.com)   │
│                                                         │
│  POST /api/ci/coverage  ← OIDC-verified, project-scoped │
│  GET  /api/projects/*   ← Cloudflare Access JWT         │
│  GET  /api/badge/*      ← public (per-project opt-in)   │
│  POST /api/webhooks/*   ← GitHub HMAC                   │
│  POST /api/admin/*      ← Cloudflare Access JWT         │
│  GET  /api/health       ← public                        │
│  *                      ← dashboard SPA (static assets) │
└───────────────────────────┬─────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────┐
│  Cloudflare D1  (your SQLite database)                  │
│  owners · projects · coverage_runs · coverage_daily     │
└─────────────────────────────────────────────────────────┘

Features

  • No static ingest secret — CI authenticates with a GitHub Actions OIDC token. The Worker verifies the signature and checks the repository claim against your registered projects, so only your registered repos can push data.
  • Private by default — all data routes are behind Cloudflare Access. Badge numbers are opt-in per repo.
  • Append-only metrics — trend history is never modified. PR jobs read baselines but never write.
  • Multi-repo — one instance tracks all the repos you install the GitHub App on.
  • Idempotent ingest — re-running CI for the same commit is a safe no-op.
  • shields.io badge format — drop a badge into any README with a one-liner.

Getting started

See docs/INSTALLATION.md for the full setup guide. The short version:

  1. Add your domain to Cloudflare (DNS must be proxied through Cloudflare)
  2. Create the D1 database and apply the migration
  3. Create a GitHub App (for webhooks + API access)
  4. Create a GitHub OAuth App (for Cloudflare Access login)
  5. Configure Cloudflare Zero Trust and deploy the Worker (the dashboard SPA deploys with it automatically)
  6. Install the GitHub App on your repos

Then add the reporting Action to each repo's CI. Run your tests first; the Action auto-detects the coverage report from the common default paths — zero config:

# .github/workflows/coverage.yml
permissions:
  id-token: write   # OIDC token for Worker auth
  checks: write     # PR Check Run

steps:
  - uses: actions/checkout@v4
  - run: npm test -- --coverage        # writes coverage/lcov.info
  - uses: CoverageTracker/coverage-tracker/.github/actions/report@v0.4.0
    with:
      worker-url: https://coverage-tracker.yourdomain.com
      # coverage-path is optional — auto-detected. Thresholds are optional too:
      # min-coverage: '80'
      # max-coverage-drop: '2'

The Action no longer runs your tests, coverage tools, or jscpd — run those yourself and point it at (or let it auto-detect) the report. See docs/generating-coverage-reports.md for the per-language commands and default paths.


Badge

Once a repo has metrics ingested and badge_enabled is turned on, add this to your README:

![Coverage](https://coverage-tracker.yourdomain.com/api/badge/owner/repo/coverage.json)

The endpoint returns shields.io endpoint format, so you can use the shields.io URL builder to customise the label and style:

![Coverage](https://img.shields.io/endpoint?url=https://coverage-tracker.yourdomain.com/api/badge/owner/repo/coverage.json)

Available metric names: coverage, complexity, duplication.

To enable the badge for a project:

# Find the project ID
npx wrangler d1 execute DB --remote --command "SELECT id, full_slug FROM projects"

# Enable badge
curl -X PATCH https://coverage-tracker.yourdomain.com/api/admin/projects/1/badge \
  -H "Cf-Access-Jwt-Assertion: <your-access-token>" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'

Project layout

.
├── migrations/           # D1 schema migrations (0001 owners/projects, 0002 coverage_runs/daily)
├── src/
│   ├── index.ts          # Hono app entry point + scheduled cron handler
│   ├── types.ts          # Bindings and shared types
│   ├── middleware/
│   │   ├── access.ts     # Cloudflare Access JWT verification
│   │   ├── oidc.ts       # GitHub Actions OIDC JWT verification
│   │   └── webhook.ts    # GitHub webhook HMAC + replay protection
│   ├── lib/
│   │   ├── db.ts         # D1 query helpers
│   │   ├── github.ts     # GitHub App token minting
│   │   ├── metrics.ts    # Metric name → column mapping
│   │   └── resync.ts     # Installation reconciliation
│   ├── db/
│   │   └── rollup.ts     # Daily coverage_runs → coverage_daily rollup + prune
│   └── routes/
│       ├── ci.ts         # POST /api/ci/coverage
│       ├── baseline.ts   # GET  /api/baseline/:owner/:repo
│       ├── api.ts        # GET  /api/projects/*
│       ├── badge.ts      # GET  /api/badge/*
│       ├── webhooks.ts   # POST /api/webhooks/github
│       └── admin.ts      # POST /api/admin/*
├── dashboard/            # SvelteKit 5 source; builds to dashboard/build/ (served by Worker)
│   └── src/routes/       # Overview + per-repo drill-in views
├── .github/
│   ├── actions/report/   # Node reporting Action (parse reports + ingest + Check Runs)
│   └── workflows/        # CI: action-test.yml, deploy.yml
├── scripts/
│   └── setup-waf-rules.mjs  # WAF skip rule for /api/ci/coverage + /api/webhooks/github
├── test/
│   └── seed-local.sql       # Local D1 seed data
├── docs/
│   ├── INSTALLATION.md   # Setup guide
│   ├── PROGRESS.md       # Phase implementation status
│   └── plans/            # Design documents
├── wrangler.example.jsonc  # Config template — copy to wrangler.json and fill in
└── .dev.vars.example       # Local secrets template — copy to .dev.vars and fill in

API reference

Method Path Auth Description
POST /api/ci/coverage OIDC token Push typed coverage metrics from CI
GET /api/projects Access List all registered owners and repos
GET /api/projects/:owner/:repo/metrics Access Trend data for one repo
GET /api/baseline/:owner/:repo OIDC token Latest value on default branch (threshold checks)
GET /api/badge/:owner/:repo/:metric.json Public shields.io endpoint — only for badge_enabled repos
POST /api/webhooks/github GitHub HMAC GitHub App installation events
POST /api/admin/resync Access Reconcile projects table against GitHub
PATCH /api/admin/projects/:id/badge Access Toggle badge visibility
GET /api/health Public Liveness check

/api/ci/coverage payload

{
  "line_coverage": 82.4,
  "branch_coverage": 79.1,
  "cyclomatic": 4.2,
  "cognitive": 2.1,
  "duplication_pct": 1.8,
  "maintainability": 95.0
}

line_coverage is required; all other fields are optional. repository, branch, and commit_sha are derived from the OIDC token claims — they are not accepted in the body.


Development

npm install
npm --prefix dashboard install             # install dashboard dependencies
cp wrangler.example.jsonc wrangler.json   # fill in your D1 database ID
cp .dev.vars.example .dev.vars             # fill in local secrets
npm run db:migrate:local                   # apply schema to local D1
npm run dev                                # start Worker + SPA (builds dashboard first)

Type-check:

npm run typecheck

Deploy:

npm run db:migrate:remote
npm run deploy

Implementation status

See docs/PROGRESS.md for a full breakdown. Current state:

Phase Description Status
1–6 Core Worker, webhooks, dashboard, reporting Action Complete
Convergence refactor (single Worker + static assets) Complete
7 "Deploy to Cloudflare" button In progress
8 Docs, OSS hygiene, public release In progress

MIT License

Copyright (c) 2026 coverage-tracker contributors

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

Self-hosted dashboard tracking code coverage, complexity, and duplication across your GitHub repos — trend charts, per-PR checks, and badges. Runs on your own Cloudflare account.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Sponsor this project

  •  

Contributors