fix: improve JiraService pagination handling

- Updated JiraService to use `nextPageToken` for pagination instead of `startAt`, aligning with the latest API documentation.
- Enhanced logging for better visibility during ticket retrieval, including page number and pagination status.
- Implemented safety checks to prevent infinite loops and added a limit for ticket retrieval.
This commit is contained in:
Julien Froidefond
2025-09-17 16:51:35 +02:00
parent 97a938c46a
commit ff5f887c6a

View File

@@ -65,25 +65,30 @@ export class JiraService {
const fields = ['id', 'key', 'summary', 'description', 'status', 'priority', 'assignee', 'project', 'issuetype', 'duedate', 'created', 'updated', 'labels'];
const allIssues: unknown[] = [];
let startAt = 0;
const maxResults = 100; // Taille des pages
let hasMorePages = true;
let nextPageToken: string | undefined = undefined;
let pageNumber = 1;
console.log('🔄 Récupération paginée des tickets Jira...');
console.log('🔄 Récupération paginée des tickets Jira (POST /search/jql avec tokens)...');
while (hasMorePages) {
const requestBody = {
while (true) {
console.log(`📄 Page ${pageNumber} ${nextPageToken ? `(token présent)` : '(première page)'}`);
// Utiliser POST /rest/api/3/search/jql avec nextPageToken selon la doc officielle
const requestBody: any = {
jql,
fields
fields,
maxResults: 50
};
console.log(`📄 Page ${Math.floor(startAt / maxResults) + 1} (tickets ${startAt + 1}-${startAt + maxResults})`);
if (nextPageToken) {
requestBody.nextPageToken = nextPageToken;
}
const response = await this.makeJiraRequest(
`/rest/api/3/search/jql?startAt=${startAt}&maxResults=${maxResults}`,
'POST',
requestBody
);
console.log(`🌐 POST /rest/api/3/search/jql avec ${nextPageToken ? 'nextPageToken' : 'première page'}`);
const response = await this.makeJiraRequest('/rest/api/3/search/jql', 'POST', requestBody);
console.log(`📡 Status réponse: ${response.status}`);
if (!response.ok) {
const errorText = await response.text();
@@ -96,7 +101,11 @@ export class JiraService {
throw new Error(`Erreur API Jira: ${response.status} ${response.statusText}. Détails: ${errorText.substring(0, 200)}`);
}
const data = await response.json() as { issues: unknown[], total: number, maxResults: number, startAt: number };
const data = await response.json() as {
issues: unknown[],
nextPageToken?: string,
isLast?: boolean
};
if (!data.issues || !Array.isArray(data.issues)) {
console.error('❌ Format de données inattendu:', data);
@@ -104,17 +113,26 @@ export class JiraService {
}
allIssues.push(...data.issues);
console.log(`${data.issues.length} tickets récupérés (total: ${allIssues.length}/${data.total || '?'})`);
console.log(`${data.issues.length} tickets récupérés (total accumulé: ${allIssues.length})`);
console.log(`🔍 Pagination info:`, {
issuesLength: data.issues.length,
hasNextPageToken: !!data.nextPageToken,
isLast: data.isLast,
pageNumber
});
// Vérifier s'il y a plus de pages
hasMorePages = data.issues.length === maxResults && allIssues.length < (data.total || Number.MAX_SAFE_INTEGER);
startAt += maxResults;
// Vérifier s'il y a plus de pages selon la doc officielle
if (data.isLast === true || !data.nextPageToken) {
console.log('🏁 Dernière page atteinte (isLast=true ou pas de nextPageToken)');
break;
}
console.log(`📊 Pagination: hasMorePages=${hasMorePages}, startAt=${startAt}, maxResults=${maxResults}`);
nextPageToken = data.nextPageToken;
pageNumber++;
// 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.');
// Sécurité: éviter les boucles infinies
if (allIssues.length >= 10000) {
console.warn(`⚠️ Limite de sécurité atteinte (${allIssues.length} tickets). Arrêt de la pagination.`);
break;
}
}