From c8119faeada2f688bcaf611c8ad2fe2878fc7c07 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Wed, 17 Sep 2025 14:06:27 +0200 Subject: [PATCH] fix: improve JiraService pagination and cleanup logic - Updated pagination logging to include total issues retrieved. - Increased safety limit for pagination from 5000 to 10000 tickets to prevent infinite loops. - Removed deprecated cleanupEpics method to streamline synchronization process. - Added check for actual changes before updating tasks to avoid unnecessary database operations. --- services/jira.ts | 93 ++++++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 63 deletions(-) diff --git a/services/jira.ts b/services/jira.ts index 9318195..48ef4f3 100644 --- a/services/jira.ts +++ b/services/jira.ts @@ -94,15 +94,17 @@ export class JiraService { } allIssues.push(...data.issues); - console.log(`✅ ${data.issues.length} tickets récupérés (total: ${allIssues.length})`); + console.log(`✅ ${data.issues.length} tickets récupérés (total: ${allIssues.length}/${data.total || '?'})`); // Vérifier s'il y a plus de pages hasMorePages = data.issues.length === maxResults && allIssues.length < (data.total || Number.MAX_SAFE_INTEGER); startAt += maxResults; - // Sécurité: éviter les boucles infinies - if (allIssues.length > 5000) { - console.warn('⚠️ Limite de sécurité atteinte (5000 tickets). Arrêt de la pagination.'); + console.log(`📊 Pagination: hasMorePages=${hasMorePages}, startAt=${startAt}, maxResults=${maxResults}`); + + // Sécurité: éviter les boucles infinies (augmenté avec la nouvelle taille de page) + if (allIssues.length > 10000) { + console.warn('⚠️ Limite de sécurité atteinte (10000 tickets). Arrêt de la pagination.'); break; } } @@ -145,61 +147,6 @@ export class JiraService { } } - /** - * Nettoie les epics Jira de la base (ne doivent plus être synchronisés) - */ - async cleanupEpics(): Promise { - try { - console.log('🧹 Nettoyage des epics Jira...'); - - // D'abord, listons toutes les tâches Jira pour voir lesquelles sont des epics - const allJiraTasks = await prisma.task.findMany({ - where: { source: 'jira' } - }); - - console.log(`🔍 ${allJiraTasks.length} tâches Jira trouvées:`); - allJiraTasks.forEach(task => { - // @ts-expect-error - jiraType existe mais n'est pas encore dans les types générés - console.log(` - ${task.jiraKey}: "${task.title}" [${task.jiraType || 'N/A'}] (ID: ${task.id})`); - }); - - // Trouver les tâches Jira qui sont des epics - // Maintenant on peut utiliser le type Jira mappé directement ! - const epicsToDelete = await prisma.task.findMany({ - where: { - source: 'jira', - // @ts-expect-error - jiraType existe mais n'est pas encore dans les types générés - jiraType: 'Epic' // Maintenant standardisé grâce au mapping - } - }); - - if (epicsToDelete.length > 0) { - // Supprimer les relations de tags d'abord - await prisma.taskTag.deleteMany({ - where: { - taskId: { in: epicsToDelete.map(task => task.id) } - } - }); - - // Supprimer les tâches epics - const result = await prisma.task.deleteMany({ - where: { - id: { in: epicsToDelete.map(task => task.id) } - } - }); - - console.log(`✅ ${result.count} epics supprimés de la base`); - return result.count; - } else { - console.log('✅ Aucun epic trouvé à nettoyer'); - return 0; - } - } catch (error) { - console.error('Erreur lors du nettoyage des epics:', error); - throw error; - } - } - /** * Synchronise les tickets Jira avec la base locale */ @@ -216,9 +163,6 @@ export class JiraService { try { console.log('🔄 Début de la synchronisation Jira...'); - // Nettoyer les epics existants (une seule fois) - await this.cleanupEpics(); - // S'assurer que le tag "From Jira" existe await this.ensureJiraTagExists(); @@ -317,6 +261,29 @@ export class JiraService { return 'skipped'; } + // Vérifier s'il y a vraiment des changements + const hasChanges = + existingTask.title !== taskData.title || + existingTask.description !== taskData.description || + existingTask.status !== taskData.status || + existingTask.priority !== taskData.priority || + (existingTask.dueDate?.getTime() || null) !== (taskData.dueDate?.getTime() || null) || + existingTask.jiraProject !== taskData.jiraProject || + existingTask.jiraKey !== taskData.jiraKey || + // @ts-expect-error - jiraType existe mais n'est pas encore dans les types générés + existingTask.jiraType !== taskData.jiraType || + existingTask.assignee !== taskData.assignee; + + if (!hasChanges) { + console.log(`⏭️ Aucun changement pour ${jiraTask.key}, skip mise à jour`); + + // S'assurer que les tags Jira sont assignés (pour les anciennes tâches) même en skip + await this.assignJiraTag(existingTask.id); + await this.assignProjectTag(existingTask.id, jiraTask.project.key); + + return 'skipped'; + } + // Mettre à jour seulement les champs Jira (pas les modifs locales) await prisma.task.update({ where: { id: existingTask.id }, @@ -331,7 +298,7 @@ export class JiraService { // @ts-expect-error - jiraType existe mais n'est pas encore dans les types générés jiraType: taskData.jiraType, assignee: taskData.assignee, - updatedAt: taskData.updatedAt + updatedAt: taskData.updatedAt // Seulement si changements réels } });