Initial commit
This commit is contained in:
111
skills/git-pr/scripts/project_cache.py
Normal file
111
skills/git-pr/scripts/project_cache.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Module de cache pour projets GitHub"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
CACHE_DIR = Path(".claude/cache")
|
||||
CACHE_FILE = CACHE_DIR / "git-projects.json"
|
||||
|
||||
|
||||
class ProjectCache:
|
||||
"""Gestion cache projets"""
|
||||
|
||||
def __init__(self):
|
||||
self.cache = self.load()
|
||||
|
||||
def load(self) -> dict:
|
||||
"""Charge cache depuis fichier"""
|
||||
if not CACHE_FILE.exists():
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
return {"updated_at": None, "projects": []}
|
||||
try:
|
||||
with open(CACHE_FILE, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except (json.JSONDecodeError, IOError):
|
||||
return {"updated_at": None, "projects": []}
|
||||
|
||||
def save(self):
|
||||
"""Sauvegarde cache vers fichier"""
|
||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
self.cache["updated_at"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
||||
with open(CACHE_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(self.cache, f, indent=2, ensure_ascii=False)
|
||||
|
||||
def find(self, query: str) -> Optional[dict]:
|
||||
"""Cherche projet par titre exact ou alias (case-insensitive)"""
|
||||
query_lower = query.lower()
|
||||
for project in self.cache.get("projects", []):
|
||||
if project["title"].lower() == query_lower:
|
||||
return project
|
||||
if query_lower in [alias.lower() for alias in project.get("aliases", [])]:
|
||||
return project
|
||||
return None
|
||||
|
||||
def add(self, project: dict):
|
||||
"""Ajoute projet au cache avec génération aliases"""
|
||||
aliases = self.generate_aliases(project["title"])
|
||||
project["aliases"] = aliases
|
||||
existing = [p for p in self.cache.get("projects", []) if p["id"] == project["id"]]
|
||||
if not existing:
|
||||
if "projects" not in self.cache:
|
||||
self.cache["projects"] = []
|
||||
self.cache["projects"].append(project)
|
||||
self.save()
|
||||
|
||||
def generate_aliases(self, title: str) -> list[str]:
|
||||
"""Génère aliases depuis titre
|
||||
|
||||
Exemples:
|
||||
- "Project Alpha" → ["project", "alpha"]
|
||||
- "Sprint 2024-Q1" → ["sprint", "2024", "q1"]
|
||||
- "Bug Tracking" → ["bug", "tracking"]
|
||||
|
||||
Logique: extraire mots-clés significatifs
|
||||
"""
|
||||
aliases = []
|
||||
words = re.findall(r'[\w]+', title.lower())
|
||||
for word in words:
|
||||
if len(word) >= 2 and word not in ['the', 'and', 'for']:
|
||||
aliases.append(word)
|
||||
return list(set(aliases))
|
||||
|
||||
def refresh_from_api(self, projects: list[dict]):
|
||||
"""Remplace cache entièrement avec données API"""
|
||||
enriched = []
|
||||
for project in projects:
|
||||
aliases = self.generate_aliases(project["title"])
|
||||
enriched.append({
|
||||
"id": project["id"],
|
||||
"title": project["title"],
|
||||
"number": project.get("number"),
|
||||
"aliases": aliases
|
||||
})
|
||||
self.cache["projects"] = enriched
|
||||
self.save()
|
||||
|
||||
def get_repo_info(self) -> str:
|
||||
"""Récupère owner/repo depuis git remote"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["git", "remote", "get-url", "origin"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
url = result.stdout.strip()
|
||||
match = re.search(r'github\.com[:/](.+/.+?)(?:\.git)?$', url)
|
||||
if match:
|
||||
repo_full = match.group(1)
|
||||
owner, _ = repo_full.split('/')
|
||||
return owner
|
||||
raise ValueError(f"Format URL invalide: {url}")
|
||||
except Exception as e:
|
||||
print(f"❌ Erreur récupération repo: {e}", file=sys.stderr)
|
||||
raise
|
||||
Reference in New Issue
Block a user