Skip to content

Badge policy

This document is the canonical reference for the README badge strip and the infrastructure that publishes its dynamic data sources. Every badge in the project's README resolves through one of three forms specified here; new badges added in the future follow the same forms or are rejected at review.

1. Background

The README originally carried static https://img.shields.io/badge/X-Y-Z URLs whose color and message never changed. Static-only badges drift away from the project's real state — a release-v0.1.0-blue badge keeps reading v0.1.0 long after v0.2.0 ships. The remediation replaces the drifting badges with dynamic forms while keeping a small set of genuinely-static badges (license, Python target version) where the displayed value rarely changes and the static form is honest.

2. Architecture

Three forms cover every badge in the project:

  1. GitHub-native workflow status badges. A workflow's badge URL has the shape https://github.com/<owner>/<repo>/actions/workflows/<file>/badge.svg and reflects the latest run on the default branch. GitHub serves the badge from the repo's metadata; the badge works for collaborators on private repos without exposing internal status to the public.
  2. shields.io endpoint badges. A shields.io endpoint badge resolves an https://img.shields.io/endpoint?url=<published-json> URL where the JSON conforms to the shields.io endpoint schema (schemaVersion, label, message, color). The published JSON lives at apothem.ahmedgad.com/badges/*.json; its content is generated by a CI workflow on every successful CI run. Endpoint badges keep private-repo metrics off public infrastructure (no public Gist, no third-party metric store) while still reflecting real-time state.
  3. shields.io static badges. A static badge has the shape https://img.shields.io/badge/<label>-<message>-<color> with no reactive data source. Reserved for values that genuinely rarely change (license identifier, Python target version).

Public-Gist publication of project metrics is excluded by design — it would leak private-repo data through a public surface. Authentication-gated shields.io endpoints over project-controlled domain are the substitute.

3. Per-badge specification

Badge Form Source URL shape
CI status GitHub-native .github/workflows/ci.yml https://github.com/Gad360/apothem/actions/workflows/ci.yml/badge.svg?branch=main
Last commit GitHub-native repo metadata https://img.shields.io/github/last-commit/Gad360/apothem
License shields.io static LICENSE (MIT) https://img.shields.io/badge/License-MIT-yellow.svg
Latest release shields.io endpoint badges/release.json https://img.shields.io/endpoint?url=https://apothem.ahmedgad.com/badges/release.json
Coverage shields.io endpoint badges/coverage.json https://img.shields.io/endpoint?url=https://apothem.ahmedgad.com/badges/coverage.json
Security shields.io endpoint badges/security.json https://img.shields.io/endpoint?url=https://apothem.ahmedgad.com/badges/security.json
Supply chain shields.io endpoint badges/supply-chain.json https://img.shields.io/endpoint?url=https://apothem.ahmedgad.com/badges/supply-chain.json
Docs shields.io endpoint badges/docs.json https://img.shields.io/endpoint?url=https://apothem.ahmedgad.com/badges/docs.json
Python version shields.io static pyproject.toml python_requires https://img.shields.io/badge/python-3.10%2B-3776AB?logo=python&logoColor=white

The CodeQL workflow is currently embedded in the security-scan job of ci.yml rather than a separate codeql.yml file; the security badge therefore consumes the endpoint JSON published by the badges workflow rather than a dedicated CodeQL workflow badge. If CodeQL later moves to its own workflow, the security badge can be promoted to a GitHub-native workflow badge without changing the README's surrounding markup.

4. JSON publication mechanism

The endpoint JSONs are produced by .github/workflows/badges.yml. The workflow:

  • Triggers on workflow_run after the ci workflow completes (and on manual workflow_dispatch for re-publication without a CI run).
  • Resolves the latest tag from git describe --tags --abbrev=0 and the parent CI conclusion from the workflow_run event.
  • Generates each JSON via jq -n so the output strictly matches the shields.io endpoint schema (schemaVersion: 1, plus label, message, color).
  • Validates every emitted JSON with jq -e before upload.
  • Uploads the directory as a workflow artifact named badges.
  • Stops at a non-functional deploy placeholder until the static-site publication workflow lands; the placeholder exits non-zero so a regression cannot ship a silently-broken pipeline.

The deployment of the artifacts to apothem.ahmedgad.com/badges/ is the responsibility of the static-site publication workflow that consumes the badges artifact uploaded above. Until that workflow lands, the README badges resolve to the same apothem.ahmedgad.com URL but the underlying JSON is published by a future workflow rather than this one's deploy step.

5. Maintenance protocol

Add a new badge by deciding the form first:

  • If the badge reflects the run-state of a CI workflow, prefer the GitHub-native form. The badge's URL is fixed by the workflow file; no publication infrastructure is needed.
  • If the badge reflects a metric (a count, a percentage, a version string, a graded label) that updates over time, use the shields.io endpoint form. Add a JSON-generation step to .github/workflows/badges.yml alongside the existing five and add the apothem.ahmedgad.com/badges/<name>.json consumer URL to the README badge strip.
  • If the badge reflects a value that genuinely rarely changes (license, language target, governance mode), use the shields.io static form. Document the change cadence in this file's per-badge table when adding the badge.

Retire a badge by removing it from the README first, then removing its JSON-generation step from the badges workflow, then removing its row from the per-badge table above. Keep the deletion atomic so the README never references a JSON the workflow no longer produces.

6. Cross-references

  • The CI workflow whose run-state the GitHub-native CI badge reflects: .github/workflows/ci.yml.
  • The badges workflow that publishes endpoint JSONs: .github/workflows/badges.yml.
  • The static-site domain that serves the JSONs: apothem.ahmedgad.com.
  • The shields.io endpoint schema reference: https://shields.io/badges/endpoint-badge.