#!/usr/bin/env tsx /** * Script de test pour vérifier la récupération des story points Jira * Usage: npm run test:story-points */ import { JiraService } from '../src/services/integrations/jira/jira'; import { userPreferencesService } from '../src/services/core/user-preferences'; async function testStoryPoints() { console.log('🧪 Test de récupération des story points Jira\n'); try { // Récupérer la config Jira pour l'utilisateur spécifié ou 'default' const userId = process.argv[2] || 'default'; const jiraConfig = await userPreferencesService.getJiraConfig(userId); if (!jiraConfig.enabled || !jiraConfig.baseUrl || !jiraConfig.email || !jiraConfig.apiToken) { console.log('❌ Configuration Jira manquante'); return; } if (!jiraConfig.projectKey) { console.log('❌ Aucun projet configuré'); return; } console.log(`📋 Test sur le projet: ${jiraConfig.projectKey}`); // Créer le service Jira const jiraService = new JiraService(jiraConfig); // Récupérer quelques tickets pour tester const jql = `project = "${jiraConfig.projectKey}" ORDER BY updated DESC`; const issues = await jiraService.searchIssues(jql); console.log(`\n📊 Analyse de ${issues.length} tickets:\n`); let totalStoryPoints = 0; let ticketsWithStoryPoints = 0; let ticketsWithoutStoryPoints = 0; const storyPointsDistribution: Record = {}; const typeDistribution: Record = {}; issues.slice(0, 20).forEach((issue, index) => { const storyPoints = issue.storyPoints || 0; const issueType = issue.issuetype.name; console.log(`${index + 1}. ${issue.key} (${issueType})`); console.log(` Titre: ${issue.summary.substring(0, 50)}...`); console.log(` Story Points: ${storyPoints > 0 ? storyPoints : 'Non défini'}`); console.log(` Statut: ${issue.status.name}`); console.log(''); if (storyPoints > 0) { ticketsWithStoryPoints++; totalStoryPoints += storyPoints; storyPointsDistribution[storyPoints] = (storyPointsDistribution[storyPoints] || 0) + 1; } else { ticketsWithoutStoryPoints++; } // Distribution par type if (!typeDistribution[issueType]) { typeDistribution[issueType] = { count: 0, totalPoints: 0 }; } typeDistribution[issueType].count++; typeDistribution[issueType].totalPoints += storyPoints; }); console.log('📈 === RÉSUMÉ ===\n'); console.log(`Total tickets analysés: ${issues.length}`); console.log(`Tickets avec story points: ${ticketsWithStoryPoints}`); console.log(`Tickets sans story points: ${ticketsWithoutStoryPoints}`); console.log(`Total story points: ${totalStoryPoints}`); console.log(`Moyenne par ticket: ${issues.length > 0 ? (totalStoryPoints / issues.length).toFixed(2) : 0}`); console.log('\n📊 Distribution des story points:'); Object.entries(storyPointsDistribution) .sort(([a], [b]) => parseInt(a) - parseInt(b)) .forEach(([points, count]) => { console.log(` ${points} points: ${count} tickets`); }); console.log('\n🏷️ Distribution par type:'); Object.entries(typeDistribution) .sort(([,a], [,b]) => b.count - a.count) .forEach(([type, stats]) => { const avgPoints = stats.count > 0 ? (stats.totalPoints / stats.count).toFixed(2) : '0'; console.log(` ${type}: ${stats.count} tickets, ${stats.totalPoints} points total, ${avgPoints} points moyen`); }); if (ticketsWithoutStoryPoints > 0) { console.log('\n⚠️ Recommandations:'); console.log('• Vérifiez que le champ "Story Points" est configuré dans votre projet Jira'); console.log('• Le champ par défaut est "customfield_10002"'); console.log('• Si votre projet utilise un autre champ, modifiez le code dans jira.ts'); console.log('• En attendant, le système utilise des estimations basées sur le type de ticket'); } } catch (error) { console.error('❌ Erreur lors du test:', error); } } // Exécution du script testStoryPoints().catch(console.error);