Files
profile-stats/scripts/language_stats.py
T

97 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 <!--LANG_STATS_START--> … <!--LANG_STATS_END-->.
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"),
]
# ---------- 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 = [
"## 📊 Language Usage\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)