Files
.profile/update_profile.py
Nathan Falvey 7f88e080cc feat: Added new organisation tracking and some basic badges.
Edited the repos table so it contains a badge displaying last commit time, and created a new table displaying current owned organisations.
2026-03-05 13:55:08 +00:00

197 lines
8.9 KiB
Python

import os
import requests
import traceback
import pprint
import datetime
import tabulate
# --- Configuration ---
GITEA_URL = "https://gitea.nathan-falvey.synology.me"
USERNAME = "nathan"
GITEA_TOKEN = os.getenv("GITEA_TOKEN")
def do_request(url, headers=None):
try:
response = requests.get(url, headers=headers)
response.raise_for_status() # Will raise an HTTPError for bad responses
return response.json()
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
def format_bytes(size_bytes):
"""Converts bytes to a human-readable string."""
if size_bytes == 0: return "0 B"
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if size_bytes < 1024.0:
return f"{size_bytes:.2f} {unit}"
size_bytes /= 1024.0
return f"{size_bytes:.2f} PB"
def get_uptime():
"""Reads Linux system uptime."""
try:
with open("/proc/uptime", "r") as f:
seconds = float(f.readline().split()[0])
return str(datetime.timedelta(seconds=int(seconds)))
except: return "Running in Container"
# a function to collect all the necessary data from the Gitea API, this will be used to gather all the information needed to build the README file. This function will make multiple API calls to gather different pieces of information and then return it in a structured format that can be easily used to build the README file.
def collect_gitea_data():
headers = {"Authorization": f"token {GITEA_TOKEN}"}
version_info = do_request(f"{GITEA_URL}/api/v1/version", headers=headers)
version_string = version_info.get("version", "Unknown") if version_info else "Unknown"
repos_info = do_request(f"{GITEA_URL}/api/v1/users/{USERNAME}/repos?type=owner", headers=headers)
organisations_info = do_request(f"{GITEA_URL}/api/v1/users/{USERNAME}/orgs", headers=headers)
repos = []
if repos_info is not None:
for repo in repos_info:
if repo.get("has_code", False):
repos.append({
"name": repo.get("name", "N/A"),
"id": repo.get("id", "N/A"),
"private": repo.get("private", False),
"archived": repo.get("archived", False),
"language": repo.get("language", "N/A"),
"size": repo.get("size", 0),
"release_count": repo.get("release_count", 0),
})
organisations = []
if organisations_info is not None:
for org in organisations_info:
organisations.append({
"name": org.get("name", "N/A"),
"id": org.get("id", "N/A"),
"private": org.get("private", False),
"description": org.get("description", "N/A"),
"full_name": org.get("full_name", "N/A"),
})
return {
"username": USERNAME,
"version": version_string,
"uptime": get_uptime(),
"repos": repos or [],
"organisations": organisations or [],
}
def do_readme_parse():
data = collect_gitea_data() # does all the API calls and collects the data into a structured format, collected once to avoid multiple API calls during the README build process, this data will be used to populate the README template with the relevant information about the Gitea instance and the user's repositories.
storage_used = sum(repo["size"] for repo in data["repos"])
languages_used = set(repo["language"] for repo in data["repos"] if repo["language"] != "N/A")
username = data["username"].capitalize() if data["username"] else "Unknown User"
md = f"# {username}'s Developer Hub\n\n"
md += f"## Welcome to {username}'s Gitea Developer Hub! This is a collection of repositories and projects that I have created and maintained on my Gitea instance. Here you can find various projects that I have worked on, ranging from personal projects to open-source contributions.\n\n"
if data["repos"]:
md += f"### 📂 Repository Breakdown\n\n"
tab_headers = ["Name", "Language", "Size", "Releases", "Private", "Archived", "Access Link", "Last Commit"]
tab_rows = []
for repo in data["repos"]:
tab_rows.append([
repo["name"],
repo["language"] if len(repo["language"]) > 1 else "N/A",
format_bytes(repo["size"]),
repo["release_count"]if repo["release_count"] > 0 else "None",
"Yes" if repo["private"] else "No",
"Yes" if repo["archived"] else "No",
f"[View]({GITEA_URL}/{USERNAME}/{repo['name']})",
f"![Gitea Last Commit](https://img.shields.io/gitea/last-commit/{USERNAME}/{repo['name']}?gitea_url=https%3A%2F%2Fgitea.nathan-falvey.synology.me&style=flat-square)"
])
md += tabulate.tabulate(tab_rows, headers=tab_headers, tablefmt="pipe")
md += "\n\n"
md += "## 📊 Stats Summary\n"
md += f"\n**Total Repositories:** {len(data['repos'])}\n\n"
md += f"**Total Storage Used:** {format_bytes(storage_used)}\n\n"
if languages_used:
md += f"### **Languages Used:**\n\n"
md += "```\n"
for lang in languages_used:
if len(lang) > 1: # Filter out empty or invalid language entries
md += f"- **{lang}**\n"
md += "```"
md += "\n"
if data["organisations"]:
md += f"### 🏢 Owned Organisation Breakdown\n\n"
tab_headers = ["Name", "Description", "Private", "Access Link"]
tab_rows = []
for org in data["organisations"]:
tab_rows.append([
org["name"],
org["description"] if len(org["description"]) > 1 else "N/A",
"Yes" if org["private"] else "No",
f"[View]({GITEA_URL}/{org['name']})"
])
md += tabulate.tabulate(tab_rows, headers=tab_headers, tablefmt="pipe")
md += "\n\n"
md += "\n"
md += "### System Information\n\n"
md += f"**Gitea Version:** {data['version']}\n\n"
md += f"**System Uptime:** {data['uptime']}\n\n"
return md
def do_readme_build():
try:
markdown = do_readme_parse().strip()
current_contents = open("README.md", "r", encoding="utf-8").read() if os.path.exists("README.md") else ""
if markdown == current_contents.strip():
print("README.md is already up to date. No changes made.")
return
with open("README.md", "w", encoding="utf-8") as f:
f.write(markdown)
print("README.md rebuilt successfully.")
except Exception as e:
print(f"Error: {e}")
pass # Placeholder for the actual README build logic
# a simple function to test the API connection and print some debug information, this will be used for debugging purposes to ensure that the API connection is working correctly and to see what data is being returned from the API calls.
def debug_request():
headers = {"Authorization": f"token {GITEA_TOKEN}"}
version_info = do_request(f"{GITEA_URL}/api/v1/version", headers=headers)
users_heatmap = do_request(f"{GITEA_URL}/api/v1/users/{USERNAME}/heatmap", headers=headers)
print(f"User Heatmap: {users_heatmap}")
version_string = version_info.get("version", "Unknown") if version_info else "Unknown"
if version_info:
print(f"Gitea Version: {version_string}")
print(f"System Uptime: {get_uptime()}")
try:
print(do_request(f"{GITEA_URL}/api/v1/version", headers=headers))
pprint.pprint(do_request(f"{GITEA_URL}/api/v1/user/repos?type=owner", headers=headers))
repos = do_request(f"{GITEA_URL}/api/v1/users/{USERNAME}/repos?type=owner", headers=headers)
if repos is not None:
print(f"Number of repos for user '{USERNAME}': {len(repos)}")
for repo in repos:
print(f"Repo Name: {repo.get('name', 'N/A')}, Repo ID: {repo.get('id', 'N/A')}")
if repo.get("has_code", False):
print(f"Repo '{repo.get('name', 'N/A')}' has code.")
print(f"Repo '{repo.get('name', 'N/A')}' is private: {repo.get('private', 'N/A')}")
print(f"Repo '{repo.get('name', 'N/A')}' is archived: {repo.get('archived', 'N/A')}")
print(f"Repo '{repo.get('name', 'N/A')}' has language: {repo.get('language', 'N/A')}")
print(f"Repo '{repo.get('name', 'N/A')}' has size: {repo.get('size', 'N/A')}")
except Exception:
print("\n" + "!"*30)
print("STACK TRACE (Line Numbers):")
traceback.print_exc()
print("!"*30)
if __name__ == "__main__":
#debug_request() # Uncomment this line to run the debug function and see the API responses and collected data
do_readme_build() # This will build the README file using the collected data from the Gitea API and the template defined in the do_readme_parse function.