diff --git a/commandes/bug_report.py b/commandes/bug_report.py index d3083fc..8a6d301 100644 --- a/commandes/bug_report.py +++ b/commandes/bug_report.py @@ -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: diff --git a/serveur_flask.py b/serveur_flask.py index ca04445..362548c 100644 --- a/serveur_flask.py +++ b/serveur_flask.py @@ -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)