revtrend
Track numeric metrics per git commit (image size, binary size, test duration, coverage, …) and visualize them over time in Grafana.
Data is keyed by commit SHA. Which commits belong to a view is answered from a bare mirror of the project's repository: the first-parent history of the selected ref, compared against a base ref.
Service
revtrend-server --config /etc/revtrend/config.toml, see
contrib/config.example.toml and
contrib/revtrend.service.
All /api/v1 endpoints require a bearer JWT from one of the configured
issuers. Roles per project: reader < writer < admin.
| Endpoint | Role | |
|---|---|---|
POST /api/v1/projects/{project}/measurements |
writer | ingest one run for a commit |
GET /api/v1/projects/{project}/series |
reader | flat rows for Grafana (metric, ref, base, from, to, labels, agg) |
GET /api/v1/projects/{project}/compare |
reader | head vs. nearest measured commit from the merge base with base |
GET /api/v1/projects |
any | projects the caller can read |
GET /api/v1/projects/{project}/refs |
reader | branches (active_since, match) |
GET /api/v1/projects/{project}/metrics |
reader | metric names and label values |
DELETE /api/v1/projects/{project}/measurements |
admin | delete by run_id or metric |
GET /auth/cli/{config,callback,poll} |
none | PKCE code relay for the CLI |
GET /healthz, GET /metrics |
none | health and Prometheus metrics |
/metrics is unauthenticated; don't expose it through the reverse proxy.
Ingest example:
curl -fsS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
--data '{"sha": "<40 hex>", "run_id": "'"$BUILD_URL"'", "metrics": [
{"name": "image.size_bytes", "value": 81234432,
"labels": {"machine": "amd64", "image": "core-image"}}]}' \
https://revtrend.example/api/v1/projects/myproject/measurements
The measurement source (ci or manual) is derived from the token issuer,
never from the request. Per commit, CI runs take precedence over manual runs.
Each measurement records the submitter as <issuer name>:<sub>, the stable
OIDC identifier. For a readable audit trail, set display_claims on an issuer
(e.g. ["preferred_username", "name"]): the first claim present in the token
is stored as submitted_name.
CLI
pipx install revtrend
export REVTREND_URL=https://revtrend.example
revtrend login
revtrend push --project myproject --sha HEAD metrics.json
revtrend compare --project myproject --head HEAD --base release/1.0
login prints a URL to open in any browser, also from an ssh session: the
service receives the login redirect and relays the authorization code to the
CLI, which redeems it with its PKCE verifier. Tokens are cached in
~/.cache/revtrend/sessions.json and refreshed automatically.
$REVTREND_TOKEN overrides the cached session.
push takes a JSON array of metrics (- reads stdin):
[{"name": "image.size_bytes", "value": 81234432,
"labels": {"machine": "amd64", "image": "core-image"}}]
--sha and --head are resolved in the current repository, so backfilling
means checking out an old commit, measuring and pushing. The commit must exist
in the remote. The run id defaults to manual-<user>-<timestamp>; pass
--run-id to make a retry idempotent.
compare prints head vs. baseline per series, or the raw response with
--json.
Development
uv sync
Tests:
uv run pytest
Static checks:
uv run ruff check
uv run ruff format --check
Entry points:
revtrend-server— HTTP API (FastAPI + uvicorn)revtrend— CLI for pushing measurements and comparing commits
Metadata
Release files for revtrend 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| revtrend-0.1.0.tar.gz | 25.3 kB | Without provenance | Details for revtrend-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| revtrend-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for revtrend-0.1.0-py3-none-any.whl |
Total release size: 53.8 kB
Release files / revtrend-0.1.0.tar.gz
| Download URL | revtrend-0.1.0.tar.gz |
|---|---|
| Size | 25.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1d60ec48ee0b387186588a7a56d1e3cbc94cac881f7aa75b3d7b79bfaf192f16
|
|
BLAKE2b-256 checksum How to use checksums |
87082073ac8541cf7971418cd672e12d4ad2c016443d2b413a246fee5b9478d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / revtrend-0.1.0-py3-none-any.whl
| Download URL | revtrend-0.1.0-py3-none-any.whl |
|---|---|
| Size | 28.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c6a28a2a1eb7385a5161f3dab9481e5a78f6e26aa2a1f0c9e496013d6cf56c3
|
|
BLAKE2b-256 checksum How to use checksums |
5498a268657ed4e397bf1469cd376dfc073f3844695ca0ab5ddad259f6933a23
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.7 {"installer":{"name":"uv","version":"0.13.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for revtrend 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.