fix(Jira Software Node): Get All Issues operation with Return All hangs (#17825)

This commit is contained in:
RomanDavydchuk
2025-08-07 10:55:56 +03:00
committed by GitHub
parent 523a55d5ee
commit 2792b6cb0a
2 changed files with 127 additions and 20 deletions

View File

@@ -76,6 +76,7 @@ export async function jiraSoftwareCloudApiRequest(
} }
export function handlePagination( export function handlePagination(
method: IHttpRequestMethods,
body: any, body: any,
query: IDataObject, query: IDataObject,
paginationType: 'offset' | 'token', paginationType: 'offset' | 'token',
@@ -83,10 +84,23 @@ export function handlePagination(
): boolean { ): boolean {
if (!responseData) { if (!responseData) {
if (paginationType === 'offset') { if (paginationType === 'offset') {
query.startAt = 0; if (method === 'GET') {
query.maxResults = 100; // Example: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-get
query.startAt = 0;
query.maxResults = 100;
} else {
// Example: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-post
body.startAt = 0;
body.maxResults = 100;
}
} else { } else {
body.maxResults = 100; if (method === 'GET') {
// Example: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-jql-get
query.maxResults = 100;
} else {
// Example: https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-search/#api-rest-api-2-search-jql-post
body.maxResults = 100;
}
} }
return true; return true;
@@ -94,10 +108,20 @@ export function handlePagination(
if (paginationType === 'offset') { if (paginationType === 'offset') {
const nextStartAt = (responseData.startAt as number) + (responseData.maxResults as number); const nextStartAt = (responseData.startAt as number) + (responseData.maxResults as number);
query.startAt = nextStartAt; if (method === 'GET') {
query.startAt = nextStartAt;
} else {
body.startAt = nextStartAt;
}
return nextStartAt < responseData.total; return nextStartAt < responseData.total;
} else { } else {
body.nextPageToken = responseData.nextPageToken as string; if (method === 'GET') {
query.nextPageToken = responseData.nextPageToken as string;
} else {
body.nextPageToken = responseData.nextPageToken as string;
}
return !!responseData.nextPageToken; return !!responseData.nextPageToken;
} }
} }
@@ -114,11 +138,11 @@ export async function jiraSoftwareCloudApiRequestAllItems(
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
let hasNextPage = handlePagination(body, query, paginationType); let hasNextPage = handlePagination(method, body, query, paginationType);
do { do {
responseData = await jiraSoftwareCloudApiRequest.call(this, endpoint, method, body, query); responseData = await jiraSoftwareCloudApiRequest.call(this, endpoint, method, body, query);
returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]); returnData.push.apply(returnData, responseData[propertyName] as IDataObject[]);
hasNextPage = handlePagination(body, query, paginationType, responseData); hasNextPage = handlePagination(method, body, query, paginationType, responseData);
} while (hasNextPage); } while (hasNextPage);
return returnData; return returnData;

View File

@@ -56,11 +56,11 @@ describe('Jira -> GenericFunctions', () => {
}); });
describe('handlePagination', () => { describe('handlePagination', () => {
it('should initialize offset pagination parameters when responseData is not provided', () => { it('should initialize offset pagination parameters with GET when responseData is not provided', () => {
const body = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const result = handlePagination(body, query, 'offset'); const result = handlePagination('GET', body, query, 'offset');
expect(result).toBe(true); expect(result).toBe(true);
expect(query.startAt).toBe(0); expect(query.startAt).toBe(0);
@@ -68,18 +68,41 @@ describe('Jira -> GenericFunctions', () => {
expect(body).toEqual({}); expect(body).toEqual({});
}); });
it('should initialize token pagination parameters when responseData is not provided', () => { it('should initialize offset pagination parameters with POST when responseData is not provided', () => {
const body: IDataObject = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const result = handlePagination(body, query, 'token'); const result = handlePagination('POST', body, query, 'offset');
expect(result).toBe(true);
expect(body.startAt).toBe(0);
expect(body.maxResults).toBe(100);
expect(query).toEqual({});
});
it('should initialize token pagination parameters with GET when responseData is not provided', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const result = handlePagination('GET', body, query, 'token');
expect(result).toBe(true);
expect(query.maxResults).toBe(100);
expect(body).toEqual({});
});
it('should initialize token pagination parameters with POST when responseData is not provided', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const result = handlePagination('POST', body, query, 'token');
expect(result).toBe(true); expect(result).toBe(true);
expect(query).toEqual({}); expect(query).toEqual({});
expect(body.maxResults).toBe(100); expect(body.maxResults).toBe(100);
}); });
it('should handle offset pagination with more pages available', () => { it('should handle offset pagination with GET and more pages available', () => {
const body: IDataObject = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const responseData = { const responseData = {
@@ -88,14 +111,30 @@ describe('Jira -> GenericFunctions', () => {
total: 250, total: 250,
}; };
const result = handlePagination(body, query, 'offset', responseData); const result = handlePagination('GET', body, query, 'offset', responseData);
expect(result).toBe(true); expect(result).toBe(true);
expect(query.startAt).toBe(100); expect(query.startAt).toBe(100);
expect(body).toEqual({}); expect(body).toEqual({});
}); });
it('should handle offset pagination with no more pages available', () => { it('should handle offset pagination with POST and more pages available', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const responseData = {
startAt: 0,
maxResults: 100,
total: 250,
};
const result = handlePagination('POST', body, query, 'offset', responseData);
expect(result).toBe(true);
expect(body.startAt).toBe(100);
expect(query).toEqual({});
});
it('should handle offset pagination with GET and no more pages available', () => {
const body: IDataObject = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const responseData = { const responseData = {
@@ -104,35 +143,79 @@ describe('Jira -> GenericFunctions', () => {
total: 250, total: 250,
}; };
const result = handlePagination(body, query, 'offset', responseData); const result = handlePagination('GET', body, query, 'offset', responseData);
expect(result).toBe(false); expect(result).toBe(false);
expect(query.startAt).toBe(300); expect(query.startAt).toBe(300);
expect(body).toEqual({}); expect(body).toEqual({});
}); });
it('should handle token pagination with more pages available', () => { it('should handle offset pagination with POST and no more pages available', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const responseData = {
startAt: 200,
maxResults: 100,
total: 250,
};
const result = handlePagination('POST', body, query, 'offset', responseData);
expect(result).toBe(false);
expect(body.startAt).toBe(300);
expect(query).toEqual({});
});
it('should handle token pagination with GET and more pages available', () => {
const body: IDataObject = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const responseData = { const responseData = {
nextPageToken: 'someToken123', nextPageToken: 'someToken123',
}; };
const result = handlePagination(body, query, 'token', responseData); const result = handlePagination('GET', body, query, 'token', responseData);
expect(result).toBe(true);
expect(query.nextPageToken).toBe('someToken123');
expect(body).toEqual({});
});
it('should handle token pagination with POST and more pages available', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const responseData = {
nextPageToken: 'someToken123',
};
const result = handlePagination('POST', body, query, 'token', responseData);
expect(result).toBe(true); expect(result).toBe(true);
expect(body.nextPageToken).toBe('someToken123'); expect(body.nextPageToken).toBe('someToken123');
expect(query).toEqual({}); expect(query).toEqual({});
}); });
it('should handle token pagination with no more pages available', () => { it('should handle token pagination with GET and no more pages available', () => {
const body: IDataObject = {}; const body: IDataObject = {};
const query: IDataObject = {}; const query: IDataObject = {};
const responseData = { const responseData = {
nextPageToken: '', nextPageToken: '',
}; };
const result = handlePagination(body, query, 'token', responseData); const result = handlePagination('GET', body, query, 'token', responseData);
expect(result).toBe(false);
expect(query.nextPageToken).toBe('');
expect(body).toEqual({});
});
it('should handle token pagination with POST and no more pages available', () => {
const body: IDataObject = {};
const query: IDataObject = {};
const responseData = {
nextPageToken: '',
};
const result = handlePagination('POST', body, query, 'token', responseData);
expect(result).toBe(false); expect(result).toBe(false);
expect(body.nextPageToken).toBe(''); expect(body.nextPageToken).toBe('');