#!/usr/bin/env python3 """ Gitea Language Stats Calculates the percentage of every programming language used in all repositories of a given account and prints a markdown table to stdout, delimited by the markers . Required environment variables -------------------------------- GITEA_BASE_URL e.g. https://gitea.example.com GITEA_TOKEN personal access-token with `repo` scope GITEA_USERNAME the account to analyse """ import os import sys import requests from collections import defaultdict from dotenv import load_dotenv load_dotenv() BASE_URL = os.getenv("GITEA_BASE_URL", "").rstrip("/") TOKEN = os.getenv("GITEA_TOKEN") USERNAME = os.getenv("GITEA_USERNAME") if not BASE_URL or not TOKEN or not USERNAME: sys.exit("GITEA_BASE_URL, GITEA_TOKEN and GITEA_USERNAME must be set") session = requests.Session() session.headers["Authorization"] = f"token {TOKEN}" # List of files whose byte-counts should be excluded from the totals. # Each tuple: (repository_name, file_path, language_name) EXCLUDE_FILES: list[tuple[str, str, str]] = [ ("ar-scavenger-hunt", "static/aframe.js", "JavaScript"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.4.html", "HTML"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.4-css.html", "HTML"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.5.html", "HTML"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.5-css.html", "HTML"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.6.html", "HTML"), ("Kingsborough-LibGuide", "groups/home/bootstrap3/Vue3-v.6-css.html", "HTML"), ] # ---------- collect repositories ---------- page = 1 repos = [] while True: resp = session.get( f"{BASE_URL}/api/v1/users/{USERNAME}/repos", params={"page": page, "limit": 50}, timeout=30, ) resp.raise_for_status() batch = resp.json() if not batch: break repos.extend(batch) page += 1 # ---------- aggregate language bytes ---------- totals: dict[str, int] = defaultdict(int) for repo in repos: langs = session.get( f"{BASE_URL}/api/v1/repos/{USERNAME}/{repo['name']}/languages", timeout=30, ).json() for lang, bytes_ in langs.items(): totals[lang] += bytes_ # ---------- subtract excluded files ---------- for repo_name, file_path, language in EXCLUDE_FILES: try: meta = session.get( f"{BASE_URL}/api/v1/repos/{USERNAME}/{repo_name}/contents/{file_path}", timeout=30, ) if meta.ok: size = meta.json().get("size", 0) totals[language] = max(0, totals[language] - size) except requests.RequestException: # Ignore failures – continue with best-effort stats pass total_bytes = sum(totals.values()) if total_bytes == 0: sys.exit("No language data returned from API.") # ---------- build markdown table ---------- pairs = sorted(totals.items(), key=lambda x: x[1], reverse=True) lines = [ "## 📊 Languages\n", ] for lang, nbytes in pairs: pct = nbytes * 100 / total_bytes bar = "█" * int(pct / 2) # up to 50 chars lines.append(f"{bar} {lang}{pct:5.1f}%\\") for line in lines: print(line)