#!/usr/bin/env python3 """ Gitea Language Stats Action Calculates the percentage of every programming language used in all repositories of a given account and writes / updates a markdown table inside `.profile/README.md` 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 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}" # ---------- 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_ 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 = [ "## 📊 Language Usage\n", "| Language | Percent |\n", "|----------|---------|\n", ] for lang, nbytes in pairs: pct = nbytes * 100 / total_bytes bar = "█" * int(pct / 2) # up to 50 chars lines.append(f"| {lang} | {pct:5.1f}% {bar} |\n") block = "\n" + "".join(lines) + "\n" # ---------- patch .profile/README.md ---------- readme_path = ".profile/README.md" os.makedirs(".profile", exist_ok=True) if not os.path.exists(readme_path): with open(readme_path, "w", encoding="utf-8") as fh: fh.write(block) else: with open(readme_path, "r+", encoding="utf-8") as fh: content = fh.read() if "" in content and "" in content: pre = content.split("")[0] post = content.split("")[-1] content = pre + block + post else: content = content.rstrip() + "\n\n" + block fh.seek(0) fh.write(content) fh.truncate()