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.
This commit is contained in:
Julien Froidefond
2025-09-17 14:06:27 +02:00
parent 625e8dba4b
commit c8119faead

View File

@@ -94,15 +94,17 @@ export class JiraService {
} }
allIssues.push(...data.issues); 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 // Vérifier s'il y a plus de pages
hasMorePages = data.issues.length === maxResults && allIssues.length < (data.total || Number.MAX_SAFE_INTEGER); hasMorePages = data.issues.length === maxResults && allIssues.length < (data.total || Number.MAX_SAFE_INTEGER);
startAt += maxResults; startAt += maxResults;
// Sécurité: éviter les boucles infinies console.log(`📊 Pagination: hasMorePages=${hasMorePages}, startAt=${startAt}, maxResults=${maxResults}`);
if (allIssues.length > 5000) {
console.warn('⚠️ Limite de sécurité atteinte (5000 tickets). Arrêt de la pagination.'); // 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; break;
} }
} }
@@ -145,61 +147,6 @@ export class JiraService {
} }
} }
/**
* Nettoie les epics Jira de la base (ne doivent plus être synchronisés)
*/
async cleanupEpics(): Promise<number> {
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 * Synchronise les tickets Jira avec la base locale
*/ */
@@ -216,9 +163,6 @@ export class JiraService {
try { try {
console.log('🔄 Début de la synchronisation Jira...'); 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 // S'assurer que le tag "From Jira" existe
await this.ensureJiraTagExists(); await this.ensureJiraTagExists();
@@ -317,6 +261,29 @@ export class JiraService {
return 'skipped'; 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) // Mettre à jour seulement les champs Jira (pas les modifs locales)
await prisma.task.update({ await prisma.task.update({
where: { id: existingTask.id }, 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 // @ts-expect-error - jiraType existe mais n'est pas encore dans les types générés
jiraType: taskData.jiraType, jiraType: taskData.jiraType,
assignee: taskData.assignee, assignee: taskData.assignee,
updatedAt: taskData.updatedAt updatedAt: taskData.updatedAt // Seulement si changements réels
} }
}); });