Skip to content

Commit a5e4c7a

Browse files
committed
Enhance error handling in upload functions to provide clearer messages for file size, API response format, and file extension errors. Improve spinner management during error reporting for better user experience.
1 parent f37da86 commit a5e4c7a

1 file changed

Lines changed: 144 additions & 21 deletions

File tree

src/core/command-runner.ts

Lines changed: 144 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,17 +2306,86 @@ export const validateAndPrepareUploadFile = (appPath: string) => {
23062306
};
23072307

23082308
export const handleUploadError = (uploadError: any, spinner: any) => {
2309-
if (uploadError.response?.data?.message?.includes('The file is too large')) {
2310-
spinner.fail(`File size exceeds the maximum allowed limit of 3 GB.`);
2311-
throw new AppcircleExitError('File size exceeds the maximum allowed limit of 3 GB.', 1);
2312-
} else if (uploadError instanceof ProgramError) {
2313-
spinner.fail(uploadError.message);
2309+
// Get error messages from different sources
2310+
// API can return error as response.data.message (object) or response.data (string)
2311+
const responseData = uploadError.response?.data;
2312+
const apiMessage = typeof responseData === 'string' ? responseData : (responseData?.message || '');
2313+
const axiosMessage = uploadError.message || '';
2314+
const statusCode = uploadError.response?.status;
2315+
2316+
// Check for file size errors first
2317+
if (apiMessage.includes('The file is too large') || axiosMessage.includes('The file is too large')) {
2318+
if (spinner && typeof spinner.stop === 'function') {
2319+
spinner.stop();
2320+
}
2321+
const errorMessage = 'File size exceeds the maximum allowed limit of 3 GB.';
2322+
console.error(errorMessage + '\n');
2323+
if (spinner && typeof spinner.fail === 'function') {
2324+
spinner.fail(errorMessage);
2325+
}
2326+
throw new AppcircleExitError('', 1);
2327+
}
2328+
2329+
// Check for ProgramError
2330+
if (uploadError instanceof ProgramError) {
2331+
if (spinner && typeof spinner.fail === 'function') {
2332+
spinner.fail(uploadError.message);
2333+
}
23142334
throw new AppcircleExitError(uploadError.message, 1);
2315-
} else if (uploadError.message && uploadError.message.includes('Cannot read properties')) {
2316-
spinner.fail(`API response format error. Please check your connection settings (AUTH_HOSTNAME and API_HOSTNAME).`);
2317-
throw new AppcircleExitError('API response format error. Please check your connection settings (AUTH_HOSTNAME and API_HOSTNAME).', 1);
23182335
}
2319-
spinner.fail(`Upload failed: ${uploadError.message || 'Unknown error'}`);
2336+
2337+
// Check for API response format errors
2338+
if (uploadError.message && uploadError.message.includes('Cannot read properties')) {
2339+
if (spinner && typeof spinner.stop === 'function') {
2340+
spinner.stop();
2341+
}
2342+
const errorMessage = 'API response format error. Please check your connection settings (AUTH_HOSTNAME and API_HOSTNAME).';
2343+
console.error(errorMessage + '\n');
2344+
if (spinner && typeof spinner.fail === 'function') {
2345+
spinner.fail(errorMessage);
2346+
}
2347+
throw new AppcircleExitError('', 1);
2348+
}
2349+
2350+
// Handle file extension errors with better messaging
2351+
// Check both API message and axios message (which may contain the API message concatenated)
2352+
const combinedMessage = (apiMessage + ' ' + axiosMessage).toLowerCase();
2353+
const isFileExtensionError =
2354+
combinedMessage.includes('extension') ||
2355+
combinedMessage.includes('file extension') ||
2356+
combinedMessage.includes('not match file extension') ||
2357+
combinedMessage.includes('match file extension') ||
2358+
combinedMessage.includes('extension is') ||
2359+
/extension\s+is\s+\.\w+/.test(combinedMessage) ||
2360+
/not\s+match\s+file\s+extension/i.test(combinedMessage) ||
2361+
// Also check if axios message contains "Bad Request" followed by extension-related text
2362+
(axiosMessage && /bad\s+request.*extension/i.test(axiosMessage.toLowerCase()));
2363+
2364+
if (isFileExtensionError) {
2365+
if (spinner && typeof spinner.stop === 'function') {
2366+
spinner.stop();
2367+
}
2368+
console.error('Invalid file type. Extension should be .ipa, .apk, or .aab.\n');
2369+
if (spinner && typeof spinner.fail === 'function') {
2370+
spinner.fail('Request failed with status code 400 Bad Request.');
2371+
}
2372+
throw new AppcircleExitError('', 1);
2373+
}
2374+
2375+
// For other errors with status code
2376+
if (statusCode) {
2377+
if (spinner && typeof spinner.fail === 'function') {
2378+
spinner.fail(`Request failed with status code ${statusCode} ${uploadError.response?.statusText || 'Bad Request'}.`);
2379+
}
2380+
if (apiMessage && apiMessage.trim()) {
2381+
console.error('\n' + apiMessage);
2382+
}
2383+
throw new AppcircleExitError(apiMessage || axiosMessage || 'Upload failed', 1);
2384+
}
2385+
2386+
if (spinner && typeof spinner.fail === 'function') {
2387+
spinner.fail(`Upload failed: ${uploadError.message || 'Unknown error'}`);
2388+
}
23202389
throw uploadError;
23212390
};
23222391

@@ -2486,13 +2555,13 @@ export const handleDistributionUpload = async (command: ProgramCommand, params:
24862555

24872556
const { expandedPath, fileName, stats } = validateAndPrepareUploadFile(params.app);
24882557

2489-
const uploadResponse = await getTestingDistributionUploadInformation({
2490-
fileName,
2491-
fileSize: stats.size,
2492-
distProfileId: params.distProfileId,
2493-
});
2494-
24952558
try {
2559+
const uploadResponse = await getTestingDistributionUploadInformation({
2560+
fileName,
2561+
fileSize: stats.size,
2562+
distProfileId: params.distProfileId,
2563+
});
2564+
24962565
await uploadArtifactWithSignedUrl({ app: expandedPath, uploadInfo: uploadResponse });
24972566
const commitFileResponse = await commitTestingDistributionFileUpload({
24982567
fileId: uploadResponse.fileId,
@@ -3715,14 +3784,68 @@ export const handleReleaseCandidateMarking = async (params: any, shouldMarkAsRel
37153784
}
37163785
};
37173786

3718-
export const handlePublishUploadError = (uploadError: any): never => {
3719-
if (uploadError.response?.data?.message?.includes('The file is too large')) {
3720-
throw new AppcircleExitError('File size exceeds the maximum allowed limit of 3 GB.', 1);
3721-
} else if (uploadError instanceof ProgramError) {
3787+
export const handlePublishUploadError = (uploadError: any, spinner?: any): never => {
3788+
// Get error messages from different sources
3789+
// API can return error as response.data.message (object) or response.data (string)
3790+
const responseData = uploadError.response?.data;
3791+
const apiMessage = typeof responseData === 'string' ? responseData : (responseData?.message || '');
3792+
const axiosMessage = uploadError.message || '';
3793+
const statusCode = uploadError.response?.status;
3794+
3795+
// Check for file size errors
3796+
if (apiMessage.includes('The file is too large') || axiosMessage.includes('The file is too large')) {
3797+
const errorMessage = 'File size exceeds the maximum allowed limit of 3 GB.';
3798+
if (spinner) {
3799+
spinner.stop();
3800+
}
3801+
console.error(errorMessage + '\n');
3802+
if (spinner) {
3803+
spinner.fail(`Request failed with status code ${statusCode || 400} Bad Request.`);
3804+
}
3805+
throw new AppcircleExitError(errorMessage, 1);
3806+
}
3807+
3808+
// Check for ProgramError
3809+
if (uploadError instanceof ProgramError) {
37223810
throw new AppcircleExitError(uploadError.message, 1);
3723-
} else if (uploadError.message && uploadError.message.includes('Cannot read properties')) {
3724-
throw new AppcircleExitError('API response format error. Please check your connection settings (AUTH_HOSTNAME and API_HOSTNAME).', 1);
37253811
}
3812+
3813+
// Check for API response format errors
3814+
if (uploadError.message && uploadError.message.includes('Cannot read properties')) {
3815+
const errorMessage = 'API response format error';
3816+
if (spinner) {
3817+
spinner.stop();
3818+
}
3819+
console.error(errorMessage + '. Please check your connection settings (AUTH_HOSTNAME and API_HOSTNAME).\n');
3820+
if (spinner) {
3821+
spinner.fail(`Request failed with status code ${statusCode || 500} ${uploadError.response?.statusText || 'Internal Server Error'}.`);
3822+
}
3823+
throw new AppcircleExitError(errorMessage, 1);
3824+
}
3825+
3826+
// Handle file extension errors with better messaging
3827+
const combinedMessage = (apiMessage + ' ' + axiosMessage).toLowerCase();
3828+
const isFileExtensionError =
3829+
combinedMessage.includes('extension') ||
3830+
combinedMessage.includes('file extension') ||
3831+
combinedMessage.includes('not match file extension') ||
3832+
combinedMessage.includes('match file extension') ||
3833+
combinedMessage.includes('extension is') ||
3834+
/extension\s+is\s+\.\w+/.test(combinedMessage) ||
3835+
/not\s+match\s+file\s+extension/i.test(combinedMessage) ||
3836+
(axiosMessage && /bad\s+request.*extension/i.test(axiosMessage.toLowerCase()));
3837+
3838+
if (isFileExtensionError) {
3839+
if (spinner) {
3840+
spinner.stop();
3841+
}
3842+
console.error('Invalid file type. Extension should be .ipa, .apk, or .aab.\n');
3843+
if (spinner) {
3844+
spinner.fail('Request failed with status code 400 Bad Request.');
3845+
}
3846+
throw new AppcircleExitError('', 1);
3847+
}
3848+
37263849
throw uploadError; // Re-throw to be caught by the outer catch
37273850
};
37283851

0 commit comments

Comments
 (0)