Code/utils/gitea.py
Stéphan Peccini 6d2e877341
feat(audit): audit qualité complet — 907→0 erreurs ruff + fix multiselect labels
- Correction des 907 erreurs ruff (pathlib, imports, nommage, simplifications, docstrings)
- Fix déduplication labels dans multiselect nœuds d'arrivée (analyse)
- Expansion 1→N label→IDs pour le Sankey (Pays d'opération)
- Ajout CLAUDE.md et document de design de l'audit
- Mise à jour .gitignore (artefacts tests exploratoires)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:52:01 +01:00

160 lines
6.2 KiB
Python

import base64
import logging
from datetime import datetime, timezone
from pathlib import Path
import requests
import streamlit as st
from dateutil import parser
from config import DEPOT_CODE, DEPOT_FICHES, DOT_FILE, ENV, ENV_CODE, GITEA_TOKEN, GITEA_URL, ORGANISATION
def lire_fichier_local(nom_fichier):
"""Lit le contenu d'un fichier local en UTF-8.
Args:
nom_fichier: Chemin vers le fichier a lire.
Returns:
str: Contenu du fichier.
"""
with Path(nom_fichier).open(encoding="utf-8") as f:
return f.read()
def charger_instructions_depuis_gitea(nom_fichier="Instructions.md"):
"""Charge le fichier Instructions.md depuis Gitea avec cache local timestamp.
Telecharge le fichier depuis Gitea uniquement si la version distante est plus
recente que la version locale. Utilise le cache local en priorite.
Args:
nom_fichier: Nom du fichier a charger. Defaut: "Instructions.md".
Returns:
str | None: Contenu du fichier en markdown, ou None si erreur sans cache.
"""
headers = {"Authorization": f"token {GITEA_TOKEN}"}
url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/{nom_fichier}?ref={ENV}"
try:
# Vérifier si une version plus récente existe sur le dépôt
fichier = Path(nom_fichier)
remote_last_modified = recuperer_date_dernier_commit(f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/commits?path={nom_fichier}&sha={ENV}")
local_last_modified = datetime.fromtimestamp(fichier.stat().st_mtime, tz=timezone.utc) if fichier.exists() else None
# Si le fichier local n'existe pas ou si la version distante est plus récente
if not local_last_modified or (remote_last_modified and remote_last_modified > local_last_modified):
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
contenu_md = base64.b64decode(data["content"]).decode("utf-8")
# Sauvegarder en local
with fichier.open("w", encoding="utf-8") as f:
f.write(contenu_md)
return contenu_md
# Lire depuis le cache local
return lire_fichier_local(nom_fichier)
except Exception as e:
st.error(f"Erreur chargement instructions Gitea : {e}")
# Essayer de charger depuis le cache local en cas d'erreur
if Path(nom_fichier).exists():
return lire_fichier_local(nom_fichier)
return None
def recuperer_date_dernier_commit(url):
"""Recupere la date du dernier commit pour un fichier via l'API Gitea.
Args:
url: URL de l'API Gitea pour les commits (format: /repos/.../commits?path=...&sha=...).
Returns:
datetime | None: Date du dernier commit en timezone-aware, ou None si erreur.
"""
headers = {"Authorization": f"token {GITEA_TOKEN}"}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
commits = response.json()
if commits:
return parser.isoparse(commits[0]["commit"]["author"]["date"])
except Exception as e:
logging.error(f"Erreur récupération commit schema : {e}")
return None
def charger_schema_depuis_gitea(fichier_local="schema_temp.txt"):
"""Charge le schema DOT depuis Gitea avec cache local base sur timestamp.
Telecharge le fichier schema DOT depuis le depot Gitea CODE uniquement si
la version distante est plus recente que la version locale (ou si aucune
version locale n'existe).
Args:
fichier_local: Chemin du fichier cache local. Defaut: "schema_temp.txt".
Returns:
str | None: "OK" si succes, None si erreur.
"""
headers = {"Authorization": f"token {GITEA_TOKEN}"}
url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_CODE}/contents/{DOT_FILE}?ref={ENV_CODE}"
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
fichier = Path(fichier_local)
remote_last_modified = recuperer_date_dernier_commit(f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_CODE}/commits?path={DOT_FILE}&sha={ENV_CODE}")
local_last_modified = datetime.fromtimestamp(fichier.stat().st_mtime, tz=timezone.utc) if fichier.exists() else None
if not local_last_modified or (remote_last_modified and remote_last_modified > local_last_modified):
dot_text = base64.b64decode(data["content"]).decode("utf-8")
with fichier.open("w", encoding="utf-8") as f:
f.write(dot_text)
return "OK"
except Exception as e:
logging.error(f"Erreur chargement schema Gitea : {e}")
return None
def charger_arborescence_fiches():
"""Charge l'arborescence complete des fiches depuis le depot Gitea.
Recupere la liste des dossiers et fichiers .md dans le repertoire Documents
du depot DEPOT_FICHES. Les resultats sont tries par ordre alphabetique.
Returns:
dict: Arborescence au format {nom_dossier: [{"nom": str, "download_url": str}, ...]}.
Retourne un dict vide en cas d'erreur.
"""
headers = {"Authorization": f"token {GITEA_TOKEN}"}
url_base = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/Documents?ref={ENV}"
try:
response = requests.get(url_base, headers=headers, timeout=10)
response.raise_for_status()
dossiers = response.json()
arbo = {}
for dossier in sorted(dossiers, key=lambda d: d['name'].lower()):
if dossier['type'] == 'dir':
dossier_name = dossier['name']
url_dossier = dossier['url']
response_dossier = requests.get(url_dossier, headers=headers, timeout=10)
response_dossier.raise_for_status()
fichiers = response_dossier.json()
fiches = sorted(
[
{"nom": f["name"], "download_url": f["download_url"]}
for f in fichiers if f["name"].endswith(".md")
],
key=lambda x: x['nom'].lower()
)
arbo[dossier_name] = fiches
return arbo
except Exception as e:
logging.error(f"Erreur chargement fiches : {e}")
return {}