Telemetry Badge #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Telemetry Badge | |
| on: | |
| schedule: | |
| - cron: "0 6 * * *" # daily at 06:00 UTC | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| update-badge: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v4 | |
| - name: Generate telemetry badge | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| SENTRY_ORG: ${{ secrets.SENTRY_ORG }} | |
| SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} | |
| BADGE_PATH: docs/badges/telemetry.json | |
| run: | | |
| set -euo pipefail | |
| if grep -q "__BADGE_REPO__" README.md; then | |
| sed -i "s#__BADGE_REPO__#${GITHUB_REPOSITORY}#g" README.md | |
| fi | |
| python - <<'PY' | |
| import json | |
| import os | |
| import sys | |
| import urllib.parse | |
| import urllib.error | |
| import urllib.request | |
| from pathlib import Path | |
| token = os.environ.get("SENTRY_AUTH_TOKEN", "").strip() | |
| org = os.environ.get("SENTRY_ORG", "").strip() | |
| project = os.environ.get("SENTRY_PROJECT", "").strip() | |
| badge_path = Path(os.environ.get("BADGE_PATH", "docs/badges/telemetry.json")) | |
| if not token or not org or not project: | |
| sys.exit("Sentry credentials (SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT) are required.") | |
| def api_get(url: str): | |
| headers = { | |
| "Authorization": f"Bearer {token}", | |
| "Content-Type": "application/json", | |
| "Accept": "application/json", | |
| "User-Agent": "svv-telemetry-badge", | |
| } | |
| req = urllib.request.Request(url, headers=headers) | |
| with urllib.request.urlopen(req, timeout=20) as resp: | |
| data = resp.read() | |
| return json.loads(data.decode()), resp.headers | |
| def latest_release_version(): | |
| url = f"https://sentry.io/api/0/projects/{org}/{project}/releases/?per_page=1" | |
| payload, _ = api_get(url) | |
| if not payload: | |
| return None | |
| return payload[0].get("version") | |
| def unresolved_count(version: str | None, proj_id: str | None): | |
| """ | |
| Return unresolved issue count. Tries release-specific first, then | |
| global unresolved. If both fail, return 0 but log the failure. | |
| """ | |
| queries = [] | |
| if version: | |
| queries.append(f'is:unresolved release:"{version}"') | |
| queries.append("is:unresolved") | |
| for query in queries: | |
| params_dict = {"query": query, "statsPeriod": "24h", "limit": 1} | |
| params = urllib.parse.urlencode(params_dict) | |
| url = f"https://sentry.io/api/0/projects/{org}/{project}/issues/?{params}" | |
| try: | |
| payload, headers = api_get(url) | |
| hits = headers.get("X-Hits") | |
| if hits is not None: | |
| try: | |
| return int(hits) | |
| except Exception: | |
| pass | |
| return len(payload) | |
| except urllib.error.HTTPError as err: | |
| body = err.read().decode(errors="ignore") | |
| print(f"[telemetry-badge] query failed ({err.code}): {err.reason} | body={body}") | |
| continue | |
| except Exception as exc: | |
| print(f"[telemetry-badge] query error: {exc}") | |
| continue | |
| # If all attempts failed, avoid breaking the workflow. | |
| return 0 | |
| version = latest_release_version() | |
| count = unresolved_count(version, None) | |
| if count == 0: | |
| color = "brightgreen" | |
| elif count < 5: | |
| color = "yellow" | |
| elif count < 15: | |
| color = "orange" | |
| else: | |
| color = "red" | |
| message_suffix = version if version else "no release" | |
| badge = { | |
| "schemaVersion": 1, | |
| "label": "telemetry", | |
| "message": f"{count} unresolved | {message_suffix}", | |
| "color": color, | |
| } | |
| badge_path.parent.mkdir(parents=True, exist_ok=True) | |
| badge_path.write_text(json.dumps(badge), encoding="utf-8") | |
| print(f"Wrote badge to {badge_path} with count={count}, version={message_suffix}") | |
| PY | |
| - name: Commit badge update | |
| uses: stefanzweifel/git-auto-commit-action@v5 | |
| with: | |
| commit_message: "chore: update telemetry badge" | |
| file_pattern: docs/badges/telemetry.json README.md |