Amélioration du suivi des issues
This commit is contained in:
parent
8736d52bf8
commit
b23c0dde53
1 changed files with 110 additions and 3 deletions
|
|
@ -58,6 +58,93 @@ def extract_issue_identifier(issue_payload: Optional[Dict[str, Any]]) -> Optiona
|
|||
return None
|
||||
|
||||
|
||||
def normalize_labels(labels: Any) -> list[str]:
|
||||
"""Normalise une liste de labels provenant de Forgejo/GitLab."""
|
||||
if not labels:
|
||||
return []
|
||||
if isinstance(labels, str):
|
||||
return [labels]
|
||||
if isinstance(labels, list):
|
||||
normalized = []
|
||||
for item in labels:
|
||||
if isinstance(item, dict):
|
||||
name = item.get("name") or item.get("title") or item.get("label") or item.get("id")
|
||||
else:
|
||||
name = item
|
||||
if name is None:
|
||||
continue
|
||||
name = str(name).strip()
|
||||
if name and name not in normalized:
|
||||
normalized.append(name)
|
||||
return normalized
|
||||
return []
|
||||
|
||||
|
||||
def extract_label_change(payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Extrait le changement de labels d’un payload d’issue."""
|
||||
changes = payload.get("changes") or {}
|
||||
labels_change = changes.get("labels") or changes.get("label")
|
||||
if not isinstance(labels_change, dict):
|
||||
return None
|
||||
|
||||
previous = normalize_labels(labels_change.get("previous"))
|
||||
current = normalize_labels(labels_change.get("current"))
|
||||
if not previous and not current:
|
||||
return None
|
||||
|
||||
added = [label for label in current if label not in previous]
|
||||
removed = [label for label in previous if label not in current]
|
||||
if not added and not removed:
|
||||
return None
|
||||
|
||||
return {
|
||||
"previous": previous,
|
||||
"current": current,
|
||||
"added": added,
|
||||
"removed": removed,
|
||||
}
|
||||
|
||||
|
||||
def calculate_progress_from_labels(labels: list[str]) -> float:
|
||||
"""Estime une progression visuelle à partir des labels présents."""
|
||||
if not labels:
|
||||
return 0.1
|
||||
|
||||
normalized = [label.lower() for label in labels]
|
||||
if any(token in normalized for token in ["done", "resolved", "fixed", "closed", "terminé", "résolu", "ok"]):
|
||||
return 1.0
|
||||
if any(token in normalized for token in ["review", "ready", "qa", "testing", "test", "validated", "validation"]):
|
||||
return 0.8
|
||||
if any(token in normalized for token in ["in progress", "working", "wip", "develop", "dev", "investigating", "progress"]):
|
||||
return 0.6
|
||||
if any(token in normalized for token in ["confirmed", "accepted", "triaged", "priority", "urgent"]):
|
||||
return 0.4
|
||||
if any(token in normalized for token in ["bug", "enhancement", "feature", "manual", "new"]):
|
||||
return 0.2
|
||||
return 0.3
|
||||
|
||||
|
||||
def build_progress_bar(progress: float, width: int = 18) -> str:
|
||||
"""Construit une barre de progression stylée en Unicode."""
|
||||
progress = max(0.0, min(1.0, progress))
|
||||
filled = int(round(progress * width))
|
||||
filled = max(0, min(width, filled))
|
||||
empty = width - filled
|
||||
percent = int(progress * 100)
|
||||
return f"{'▰' * filled}{'▱' * empty} {percent}%"
|
||||
|
||||
|
||||
def color_from_progress(progress: float) -> disnake.Color:
|
||||
"""Retourne une couleur violet→bleu selon la progression."""
|
||||
progress = max(0.0, min(1.0, progress))
|
||||
purple = (117, 82, 255)
|
||||
blue = (74, 144, 255)
|
||||
r = int(purple[0] + (blue[0] - purple[0]) * progress)
|
||||
g = int(purple[1] + (blue[1] - purple[1]) * progress)
|
||||
b = int(purple[2] + (blue[2] - purple[2]) * progress)
|
||||
return disnake.Color.from_rgb(r, g, b)
|
||||
|
||||
|
||||
def load_tracking():
|
||||
"""Charge le tracking depuis gitlab_issues.json (avec migration automatique)"""
|
||||
tracking = {}
|
||||
|
|
@ -397,12 +484,32 @@ class BugReport(commands.Cog):
|
|||
pass
|
||||
|
||||
elif event_type == "issue":
|
||||
# 🕵️ 5. GESTION DES CLÔTURES (Optionnel : si tu fermes le ticket sur Forgejo)
|
||||
action = payload.get("object_attributes", {}).get("action") or payload.get("action")
|
||||
state = payload.get("object_attributes", {}).get("state") or payload.get("issue", {}).get("state")
|
||||
label_change = extract_label_change(payload)
|
||||
|
||||
if label_change:
|
||||
current_labels = label_change["current"]
|
||||
progress = calculate_progress_from_labels(current_labels)
|
||||
bar = build_progress_bar(progress)
|
||||
added = ", ".join(label_change["added"]) if label_change["added"] else "aucun"
|
||||
removed = ", ".join(label_change["removed"]) if label_change["removed"] else "aucun"
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
title="📈 Évolution du ticket",
|
||||
description=f"Le suivi de **{issue_title}** a été mis à jour après un changement de labels.",
|
||||
color=color_from_progress(progress),
|
||||
)
|
||||
embed.add_field(name="Progression", value=bar, inline=False)
|
||||
embed.add_field(name="Labels ajoutés", value=added if added != "aucun" else "Aucun", inline=True)
|
||||
embed.add_field(name="Labels retirés", value=removed if removed != "aucun" else "Aucun", inline=True)
|
||||
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
|
||||
await user.send(embed=embed)
|
||||
kuby_logger.info(f"Notification de progression envoyée à {user} pour l'issue #{issue_iid}")
|
||||
except Exception as e:
|
||||
kuby_logger.error(f"Erreur notification progression: {e}")
|
||||
|
||||
is_closing_now = action in ["close", "closed"] or state == "closed"
|
||||
|
||||
if is_closing_now:
|
||||
try:
|
||||
embed = disnake.Embed(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue