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:
@@ -65,25 +65,30 @@ export class JiraService {
|
|||||||
const fields = ['id', 'key', 'summary', 'description', 'status', 'priority', 'assignee', 'project', 'issuetype', 'duedate', 'created', 'updated', 'labels'];
|
const fields = ['id', 'key', 'summary', 'description', 'status', 'priority', 'assignee', 'project', 'issuetype', 'duedate', 'created', 'updated', 'labels'];
|
||||||
|
|
||||||
const allIssues: unknown[] = [];
|
const allIssues: unknown[] = [];
|
||||||
let startAt = 0;
|
let nextPageToken: string | undefined = undefined;
|
||||||
const maxResults = 100; // Taille des pages
|
let pageNumber = 1;
|
||||||
let hasMorePages = true;
|
|
||||||
|
|
||||||
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) {
|
while (true) {
|
||||||
const requestBody = {
|
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,
|
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(
|
console.log(`🌐 POST /rest/api/3/search/jql avec ${nextPageToken ? 'nextPageToken' : 'première page'}`);
|
||||||
`/rest/api/3/search/jql?startAt=${startAt}&maxResults=${maxResults}`,
|
|
||||||
'POST',
|
const response = await this.makeJiraRequest('/rest/api/3/search/jql', 'POST', requestBody);
|
||||||
requestBody
|
|
||||||
);
|
console.log(`📡 Status réponse: ${response.status}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorText = await response.text();
|
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)}`);
|
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)) {
|
if (!data.issues || !Array.isArray(data.issues)) {
|
||||||
console.error('❌ Format de données inattendu:', data);
|
console.error('❌ Format de données inattendu:', data);
|
||||||
@@ -104,17 +113,26 @@ export class JiraService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allIssues.push(...data.issues);
|
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
|
// Vérifier s'il y a plus de pages selon la doc officielle
|
||||||
hasMorePages = data.issues.length === maxResults && allIssues.length < (data.total || Number.MAX_SAFE_INTEGER);
|
if (data.isLast === true || !data.nextPageToken) {
|
||||||
startAt += maxResults;
|
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)
|
// Sécurité: éviter les boucles infinies
|
||||||
if (allIssues.length > 10000) {
|
if (allIssues.length >= 10000) {
|
||||||
console.warn('⚠️ Limite de sécurité atteinte (10000 tickets). Arrêt de la pagination.');
|
console.warn(`⚠️ Limite de sécurité atteinte (${allIssues.length} tickets). Arrêt de la pagination.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user