V0.9 de l'amélioration du suivi des issues #262
1 changed files with 80 additions and 17 deletions
|
|
@ -6,6 +6,7 @@ import logging
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import re
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional
|
||||||
from utils.premium import check_premium_tier
|
from utils.premium import check_premium_tier
|
||||||
|
|
||||||
|
|
@ -47,14 +48,37 @@ def extract_issue_iid(payload: Dict[str, Any]) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def extract_issue_identifier(issue_payload: Optional[Dict[str, Any]]) -> Optional[str]:
|
def extract_issue_identifier(issue_payload: Optional[Any]) -> Optional[str]:
|
||||||
"""Récupère un identifiant stable à stocker dans le tracking."""
|
"""Récupère un identifiant stable à stocker dans le tracking, même si le payload est imbriqué."""
|
||||||
if not isinstance(issue_payload, dict):
|
if issue_payload is None:
|
||||||
return None
|
return None
|
||||||
for key in ("iid", "number", "id"):
|
|
||||||
value = issue_payload.get(key)
|
if isinstance(issue_payload, dict):
|
||||||
if value not in (None, ""):
|
for key in ("iid", "number", "id", "issue_id"):
|
||||||
return str(value)
|
value = issue_payload.get(key)
|
||||||
|
if value not in (None, ""):
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
for key in ("html_url", "web_url", "url"):
|
||||||
|
value = issue_payload.get(key)
|
||||||
|
if isinstance(value, str):
|
||||||
|
match = re.search(r"/(?:issues|tickets)/([0-9]+)", value)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
|
||||||
|
for value in issue_payload.values():
|
||||||
|
found = extract_issue_identifier(value)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(issue_payload, list):
|
||||||
|
for item in issue_payload:
|
||||||
|
found = extract_issue_identifier(item)
|
||||||
|
if found:
|
||||||
|
return found
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -187,6 +211,26 @@ def color_from_progress(progress: float) -> disnake.Color:
|
||||||
return disnake.Color.from_rgb(r, g, b)
|
return disnake.Color.from_rgb(r, g, b)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_tracking_issue_id(issue_iid: Any) -> Optional[str]:
|
||||||
|
"""Normalise un identifiant d’issue pour le tracking, en ne conservant que les valeurs numériques valides."""
|
||||||
|
if issue_iid is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(issue_iid, int):
|
||||||
|
return str(issue_iid)
|
||||||
|
|
||||||
|
if isinstance(issue_iid, str):
|
||||||
|
normalized = issue_iid.strip()
|
||||||
|
if not normalized:
|
||||||
|
return None
|
||||||
|
if normalized.lower() in {"none", "null", "nan", "undefined"}:
|
||||||
|
return None
|
||||||
|
if re.fullmatch(r"\d+", normalized):
|
||||||
|
return normalized
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def load_tracking():
|
def load_tracking():
|
||||||
"""Charge le tracking depuis gitlab_issues.json (avec migration automatique)"""
|
"""Charge le tracking depuis gitlab_issues.json (avec migration automatique)"""
|
||||||
tracking = {}
|
tracking = {}
|
||||||
|
|
@ -202,14 +246,23 @@ def load_tracking():
|
||||||
try:
|
try:
|
||||||
with open(LEGACY_REPORTS_FILE, "r", encoding="utf-8") as f:
|
with open(LEGACY_REPORTS_FILE, "r", encoding="utf-8") as f:
|
||||||
legacy_data = json.load(f)
|
legacy_data = json.load(f)
|
||||||
for issue_iid, user_id in legacy_data.items():
|
|
||||||
if issue_iid not in tracking:
|
migrated_count = 0
|
||||||
tracking[issue_iid] = {
|
for raw_issue_iid, user_id in legacy_data.items():
|
||||||
"requester_id": user_id,
|
issue_iid = normalize_tracking_issue_id(raw_issue_iid)
|
||||||
"last_note_id": 0,
|
if not issue_iid:
|
||||||
"type": "legacy_report"
|
kuby_logger.debug(f"Ignoré pendant la migration de tracking: issue_id={raw_issue_iid}")
|
||||||
}
|
continue
|
||||||
kuby_logger.info(f"Migration automatique: {len(legacy_data)} issues fusionnées")
|
if issue_iid in tracking:
|
||||||
|
continue
|
||||||
|
tracking[issue_iid] = {
|
||||||
|
"requester_id": user_id,
|
||||||
|
"last_note_id": 0,
|
||||||
|
"type": "legacy_report"
|
||||||
|
}
|
||||||
|
migrated_count += 1
|
||||||
|
|
||||||
|
kuby_logger.info(f"Migration automatique: {migrated_count} issue(s) fusionnée(s) depuis l'historique")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
kuby_logger.error(f"Erreur migration gitlab_reports.json: {e}")
|
kuby_logger.error(f"Erreur migration gitlab_reports.json: {e}")
|
||||||
|
|
||||||
|
|
@ -277,7 +330,12 @@ class BugReportModal(disnake.ui.Modal):
|
||||||
if result:
|
if result:
|
||||||
issue_iid = extract_issue_identifier(result)
|
issue_iid = extract_issue_identifier(result)
|
||||||
if not issue_iid:
|
if not issue_iid:
|
||||||
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab")
|
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab. Tentative de fallback par titre.")
|
||||||
|
lookup = await gitlab_client.find_issue_by_title(f"[MANUAL] {bug_title}", state="open")
|
||||||
|
issue_iid = extract_issue_identifier(lookup)
|
||||||
|
|
||||||
|
if not issue_iid:
|
||||||
|
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée après fallback. Payload reçu: %s", result)
|
||||||
await interaction.edit_original_response(content="✅ Votre rapport a été envoyé, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
|
await interaction.edit_original_response(content="✅ Votre rapport a été envoyé, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -346,7 +404,12 @@ class FeatureSuggestionModal(disnake.ui.Modal):
|
||||||
if result:
|
if result:
|
||||||
issue_iid = extract_issue_identifier(result)
|
issue_iid = extract_issue_identifier(result)
|
||||||
if not issue_iid:
|
if not issue_iid:
|
||||||
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab")
|
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab. Tentative de fallback par titre.")
|
||||||
|
lookup = await gitlab_client.find_issue_by_title(f"[SUGGESTION] {suggestion_title}", state="open")
|
||||||
|
issue_iid = extract_issue_identifier(lookup)
|
||||||
|
|
||||||
|
if not issue_iid:
|
||||||
|
kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée après fallback. Payload reçu: %s", result)
|
||||||
await interaction.edit_original_response(content="✅ Votre suggestion a été envoyée, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
|
await interaction.edit_original_response(content="✅ Votre suggestion a été envoyée, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue