V0.5 de l'amélioration du suivi des issues

This commit is contained in:
Mathis 2026-07-12 15:59:29 +02:00
parent 016ac85bc7
commit 54c5ef471e
2 changed files with 89 additions and 13 deletions

View file

@ -134,19 +134,38 @@ def calculate_progress_from_labels(labels: list[str]) -> float:
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"]):
if any(token in normalized for token in ["done", "resolved", "fixed", "closed", "terminé", "résolu", "ok", "completed"]):
return 1.0
if any(token in normalized for token in ["review", "ready", "qa", "testing", "test", "validated", "validation"]):
if any(token in normalized for token in ["review", "ready", "qa", "testing", "test", "validated", "validation", "verif", "vérif"]):
return 0.8
if any(token in normalized for token in ["in progress", "working", "wip", "develop", "dev", "investigating", "progress"]):
if any(token in normalized for token in ["in progress", "working", "wip", "develop", "dev", "investigating", "progress", "travail"]):
return 0.6
if any(token in normalized for token in ["confirmed", "accepted", "triaged", "priority", "urgent"]):
if any(token in normalized for token in ["confirmed", "accepted", "triaged", "priority", "urgent", "prioritaire"]):
return 0.4
if any(token in normalized for token in ["bug", "enhancement", "feature", "manual", "new"]):
if any(token in normalized for token in ["bug", "enhancement", "feature", "manual", "new", "suggestion"]):
return 0.2
return 0.3
def build_status_message_from_labels(labels: list[str]) -> str:
"""Traduit les labels en un message utilisateur lisible."""
if not labels:
return "⏳ La demande évolue et l'équipe suit son avancement."
normalized = [str(label).lower() for label in labels if str(label).strip()]
if any(token in normalized for token in ["done", "resolved", "fixed", "closed", "terminé", "résolu", "completed", "ok"]):
return "✅ La demande a été traitée et est prête à être déployée."
if any(token in normalized for token in ["review", "qa", "testing", "test", "validated", "validation", "verif", "vérif"]):
return "🔎 La demande est en cours de vérification par l'équipe."
if any(token in normalized for token in ["in progress", "working", "wip", "develop", "dev", "investigating", "progress", "travail"]):
return "🛠️ L'équipe est en train de travailler dessus."
if any(token in normalized for token in ["confirmed", "accepted", "triaged", "priority", "urgent", "prioritaire"]):
return "🗂️ La demande a bien été prise en compte et est en cours d'analyse."
if any(token in normalized for token in ["bug", "enhancement", "feature", "manual", "new", "suggestion"]):
return "📝 La demande a été reçue et sera étudiée prochainement."
return "⏳ La demande évolue et l'équipe suit son avancement."
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))
@ -394,6 +413,7 @@ class BugReport(commands.Cog):
try:
app = web.Application()
app.router.add_post('/bot_event', self.handle_bot_event)
app.router.add_post('/deployment_complete', self.handle_deployment_complete)
self.runner = web.AppRunner(app)
await self.runner.setup()
self.site = web.TCPSite(self.runner, '127.0.0.1', 5001, reuse_address=True)
@ -414,6 +434,48 @@ class BugReport(commands.Cog):
kuby_logger.error(f"Error during webhook server cleanup: {e}")
self.bot.loop.create_task(cleanup())
async def handle_deployment_complete(self, request):
"""Notifie les demandeurs dont la fonctionnalité a été intégrée et attend le prochain déploiement."""
try:
await request.json()
for issue_iid, issue_data in list(self.issue_data.items()):
if not issue_data.get("pending_deployment_notification"):
continue
requester_id = issue_data.get("requester_id")
if not requester_id:
continue
user = self.bot.get_user(requester_id)
if not user:
try:
user = await self.bot.fetch_user(requester_id)
except Exception:
continue
try:
embed = disnake.Embed(
title="🚀 Fonctionnalité disponible !",
description=(
"✅ Votre demande est désormais fonctionnelle sur le bot.\n\n"
"Merci encore pour votre contribution et votre patience."
),
color=disnake.Color.blurple()
)
if self.bot.user.display_avatar:
embed.set_thumbnail(url=self.bot.user.display_avatar.url)
await user.send(embed=embed)
except Exception as e:
kuby_logger.warning(f"Impossible d'envoyer la notification de déploiement à {user}: {e}")
issue_data["pending_deployment_notification"] = False
save_tracking(self.issue_data)
return web.json_response({"status": "notified"}, status=200)
except Exception as e:
kuby_logger.error(f"Error handling deployment complete: {e}")
return web.json_response({"status": "error", "message": str(e)}, status=500)
async def handle_bot_event(self, request):
"""Gère les webhooks (adapté pour GitLab ET Forgejo)"""
try:
@ -515,17 +577,14 @@ class BugReport(commands.Cog):
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"
status_message = build_status_message_from_labels(current_labels)
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.",
description=f"Le suivi de **{issue_title}** a été mis à jour.\n\n{status_message}",
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}")
@ -534,10 +593,16 @@ class BugReport(commands.Cog):
is_closing_now = action in ["close", "closed"] or state == "closed"
if is_closing_now:
self.issue_data[issue_iid]["pending_deployment_notification"] = True
save_tracking(self.issue_data)
try:
embed = disnake.Embed(
title="🛠️ Bug / Suggestion Terminé(e) !",
description=f"Bonne nouvelle ! Votre signalement **{issue_title}** a été marqué comme terminé ou résolu.\n\n🚀 **Prochaine étape :** La mise à jour arrive prochainement !\n✨ Merci pour votre aide !",
title="🛠️ Demande traitée !",
description=(
f"Bonne nouvelle ! Votre demande **{issue_title}** a été intégrée au code du bot.\n\n"
"✅ Elle n'est pas encore disponible au public, mais elle est maintenant prise en charge côté développement.\n\n"
"🔜 Lors du prochain déploiement, Kuby vous informera qu'elle est désormais fonctionnelle."
),
color=disnake.Color.green()
)
if self.bot.user.display_avatar:

View file

@ -1,4 +1,4 @@
import os, subprocess, threading, requests
import os, subprocess, threading, requests, time
# Nettoyer les variables de certificats SSL corrompues ou obsolètes pour éviter les crashs TLS
os.environ.pop("REQUESTS_CA_BUNDLE", None)
os.environ.pop("SSL_CERT_FILE", None)
@ -88,6 +88,17 @@ def run_mep_logic(author, commit_msg, branch="main"):
# 3. Redémarrage via systemd
subprocess.run(["systemctl", "restart", "kuby-bot.service"], check=True, capture_output=True, text=True)
# 4. Notifier le bot que le déploiement est terminé pour les issues en attente
for attempt in range(6):
try:
requests.post("http://127.0.0.1:5001/deployment_complete", timeout=5)
break
except Exception:
if attempt < 5:
time.sleep(2)
else:
print("[WARN] Impossible d'envoyer la notification de déploiement au bot", flush=True)
duration = (datetime.now() - start_time).total_seconds()
msg = f"✅ **Déploiement réussi en {duration:.2f}s**\nLe bot est à jour sur Forgejo et redémarré."
send_discord_log("VALIDÉ", msg, 3066993, author, commit_msg)