Skip to content

Commit 03cae4f

Browse files
refactor: implement proper error handling with concise AxiosError formatting and last-resort exception handlers
1 parent a156c51 commit 03cae4f

File tree

3 files changed

+150
-38
lines changed

3 files changed

+150
-38
lines changed

dist/main/index.js

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33316,6 +33316,69 @@ function wrappy (fn, cb) {
3331633316
}
3331733317

3331833318

33319+
/***/ }),
33320+
33321+
/***/ 823:
33322+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
33323+
33324+
"use strict";
33325+
33326+
var __importDefault = (this && this.__importDefault) || function (mod) {
33327+
return (mod && mod.__esModule) ? mod : { "default": mod };
33328+
};
33329+
Object.defineProperty(exports, "__esModule", ({ value: true }));
33330+
exports.formatAxiosError = formatAxiosError;
33331+
exports.logAxiosError = logAxiosError;
33332+
exports.isAxiosError = isAxiosError;
33333+
const axios_1 = __importDefault(__nccwpck_require__(8757));
33334+
/**
33335+
* Formats an AxiosError into a concise, readable error message
33336+
* Includes: HTTP method, URL, status code, and response body (typically error message)
33337+
* Excludes verbose config details that cause thousands of lines of output
33338+
*/
33339+
function formatAxiosError(error) {
33340+
const parts = [];
33341+
if (error.config) {
33342+
if (error.config.method) {
33343+
parts.push(`Method: ${error.config.method.toUpperCase()}`);
33344+
}
33345+
if (error.config.url) {
33346+
parts.push(`URL: ${error.config.url}`);
33347+
}
33348+
}
33349+
if (error.response) {
33350+
parts.push(`Status: ${error.response.status}`);
33351+
if (error.response.data) {
33352+
const responseData = error.response.data;
33353+
if (typeof responseData === 'string') {
33354+
parts.push(`Response: ${responseData}`);
33355+
}
33356+
else if (typeof responseData === 'object') {
33357+
parts.push(`Response: ${JSON.stringify(responseData)}`);
33358+
}
33359+
}
33360+
}
33361+
else if (error.message) {
33362+
parts.push(`Error: ${error.message}`);
33363+
}
33364+
return parts.join(' | ');
33365+
}
33366+
/**
33367+
* Logs an AxiosError with concise formatting
33368+
* HTTP errors are considered "expected" and are treated as fully handled
33369+
*/
33370+
function logAxiosError(error, coreAdapter, context) {
33371+
const formattedError = formatAxiosError(error);
33372+
coreAdapter.error(`${context}: ${formattedError}`);
33373+
}
33374+
/**
33375+
* Determines if an error is an AxiosError
33376+
*/
33377+
function isAxiosError(error) {
33378+
return axios_1.default.isAxiosError(error);
33379+
}
33380+
33381+
3331933382
/***/ }),
3332033383

3332133384
/***/ 6144:
@@ -33357,6 +33420,7 @@ const axios_1 = __importDefault(__nccwpck_require__(8757));
3335733420
const fs = __importStar(__nccwpck_require__(7147));
3335833421
const path = __importStar(__nccwpck_require__(1017));
3335933422
const os = __importStar(__nccwpck_require__(2037));
33423+
const error_utils_1 = __nccwpck_require__(823);
3336033424
function loadTokenFromFile(coreAdapter) {
3336133425
const tempDir = process.env.RUNNER_TEMP || os.tmpdir();
3336233426
const tokenFilePath = path.join(tempDir, 'meshstack_token.json');
@@ -33395,14 +33459,8 @@ async function loadBuildingBlockRunFromUrl(url, token, coreAdapter) {
3339533459
return buildingBlockRunJson;
3339633460
}
3339733461
catch (fetchError) {
33398-
if (axios_1.default.isAxiosError(fetchError)) {
33399-
if (fetchError.response) {
33400-
coreAdapter.error(`Failed to fetch building block run: ${JSON.stringify(fetchError.response.data)}`);
33401-
coreAdapter.error(`Status code: ${fetchError.response.status}`);
33402-
}
33403-
else {
33404-
coreAdapter.error(`Fetch error message: ${fetchError.message}`);
33405-
}
33462+
if ((0, error_utils_1.isAxiosError)(fetchError)) {
33463+
(0, error_utils_1.logAxiosError)(fetchError, coreAdapter, 'Failed to fetch building block run');
3340633464
}
3340733465
else {
3340833466
coreAdapter.error(`Unexpected error during fetch: ${fetchError}`);
@@ -33455,14 +33513,8 @@ async function registerSource(buildingBlockRunUrl, requestPayload, requestHeader
3345533513
coreAdapter.setOutput('token_file', tokenFilePath);
3345633514
}
3345733515
catch (registerError) {
33458-
if (axios_1.default.isAxiosError(registerError)) {
33459-
if (registerError.response) {
33460-
coreAdapter.error(`Register source error response: ${JSON.stringify(registerError.response.data)}`);
33461-
coreAdapter.error(`Status code: ${registerError.response.status}`);
33462-
}
33463-
else {
33464-
coreAdapter.error(`Register source error message: ${registerError.message}`);
33465-
}
33516+
if ((0, error_utils_1.isAxiosError)(registerError)) {
33517+
(0, error_utils_1.logAxiosError)(registerError, coreAdapter, 'Failed to register source');
3346633518
}
3346733519
else {
3346833520
coreAdapter.error(`Unexpected error: ${registerError}`);
@@ -33505,18 +33557,25 @@ async function runRegisterSource(coreAdapter = core, githubContext = github) {
3350533557
await registerSource(runUrl, requestPayload, requestHeaders, tokenFilePath, coreAdapter);
3350633558
}
3350733559
catch (error) {
33560+
// Exception handler of last resort
3350833561
if (error instanceof Error) {
3350933562
coreAdapter.setFailed(error.message);
33510-
throw error;
3351133563
}
3351233564
else {
33513-
coreAdapter.setFailed('An unknown error occurred');
33514-
throw error;
33565+
coreAdapter.setFailed(`An unknown error occurred: ${error}`);
3351533566
}
33567+
throw error;
3351633568
}
3351733569
}
3351833570
async function run() {
33519-
await runRegisterSource(core, github);
33571+
try {
33572+
await runRegisterSource(core, github);
33573+
}
33574+
catch (error) {
33575+
// Last-resort exception handler: prevent unhandled rejections
33576+
// The error has already been logged and setFailed has been called
33577+
process.exit(1);
33578+
}
3352033579
}
3352133580
// Only run if this file is executed directly (not imported)
3352233581
if (require.main === require.cache[eval('__filename')]) {

src/error-utils.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import axios, { AxiosError } from 'axios';
2+
3+
export interface CoreAdapter {
4+
error: (message: string) => void;
5+
debug: (message: string) => void;
6+
}
7+
8+
/**
9+
* Formats an AxiosError into a concise, readable error message
10+
* Includes: HTTP method, URL, status code, and response body (typically error message)
11+
* Excludes verbose config details that cause thousands of lines of output
12+
*/
13+
export function formatAxiosError(error: AxiosError): string {
14+
const parts: string[] = [];
15+
16+
if (error.config) {
17+
if (error.config.method) {
18+
parts.push(`Method: ${error.config.method.toUpperCase()}`);
19+
}
20+
if (error.config.url) {
21+
parts.push(`URL: ${error.config.url}`);
22+
}
23+
}
24+
25+
if (error.response) {
26+
parts.push(`Status: ${error.response.status}`);
27+
if (error.response.data) {
28+
const responseData = error.response.data;
29+
if (typeof responseData === 'string') {
30+
parts.push(`Response: ${responseData}`);
31+
} else if (typeof responseData === 'object') {
32+
parts.push(`Response: ${JSON.stringify(responseData)}`);
33+
}
34+
}
35+
} else if (error.message) {
36+
parts.push(`Error: ${error.message}`);
37+
}
38+
39+
return parts.join(' | ');
40+
}
41+
42+
/**
43+
* Logs an AxiosError with concise formatting
44+
* HTTP errors are considered "expected" and are treated as fully handled
45+
*/
46+
export function logAxiosError(error: AxiosError, coreAdapter: CoreAdapter, context: string): void {
47+
const formattedError = formatAxiosError(error);
48+
coreAdapter.error(`${context}: ${formattedError}`);
49+
}
50+
51+
/**
52+
* Determines if an error is an AxiosError
53+
*/
54+
export function isAxiosError(error: any): error is AxiosError {
55+
return axios.isAxiosError(error);
56+
}

src/index.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import axios from 'axios';
44
import * as fs from 'fs';
55
import * as path from 'path';
66
import * as os from 'os';
7+
import { logAxiosError, isAxiosError } from './error-utils';
78

89
// allows stubbing @actions/core in tests
910
export interface CoreAdapter {
@@ -142,13 +143,8 @@ async function loadBuildingBlockRunFromUrl(
142143
coreAdapter.debug(`Fetched Building Block Run: ${JSON.stringify(buildingBlockRunJson)}`);
143144
return buildingBlockRunJson;
144145
} catch (fetchError) {
145-
if (axios.isAxiosError(fetchError)) {
146-
if (fetchError.response) {
147-
coreAdapter.error(`Failed to fetch building block run: ${JSON.stringify(fetchError.response.data)}`);
148-
coreAdapter.error(`Status code: ${fetchError.response.status}`);
149-
} else {
150-
coreAdapter.error(`Fetch error message: ${fetchError.message}`);
151-
}
146+
if (isAxiosError(fetchError)) {
147+
logAxiosError(fetchError, coreAdapter, 'Failed to fetch building block run');
152148
} else {
153149
coreAdapter.error(`Unexpected error during fetch: ${fetchError}`);
154150
}
@@ -220,13 +216,8 @@ async function registerSource(
220216
coreAdapter.setOutput('response', response.data);
221217
coreAdapter.setOutput('token_file', tokenFilePath);
222218
} catch (registerError) {
223-
if (axios.isAxiosError(registerError)) {
224-
if (registerError.response) {
225-
coreAdapter.error(`Register source error response: ${JSON.stringify(registerError.response.data)}`);
226-
coreAdapter.error(`Status code: ${registerError.response.status}`);
227-
} else {
228-
coreAdapter.error(`Register source error message: ${registerError.message}`);
229-
}
219+
if (isAxiosError(registerError)) {
220+
logAxiosError(registerError, coreAdapter, 'Failed to register source');
230221
} else {
231222
coreAdapter.error(`Unexpected error: ${registerError}`);
232223
}
@@ -280,18 +271,24 @@ export async function runRegisterSource(
280271
// Register the source
281272
await registerSource(runUrl, requestPayload, requestHeaders, tokenFilePath, coreAdapter);
282273
} catch (error) {
274+
// Exception handler of last resort
283275
if (error instanceof Error) {
284276
coreAdapter.setFailed(error.message);
285-
throw error;
286277
} else {
287-
coreAdapter.setFailed('An unknown error occurred');
288-
throw error;
278+
coreAdapter.setFailed(`An unknown error occurred: ${error}`);
289279
}
280+
throw error;
290281
}
291282
}
292283

293284
async function run() {
294-
await runRegisterSource(core, github);
285+
try {
286+
await runRegisterSource(core, github);
287+
} catch (error) {
288+
// Last-resort exception handler: prevent unhandled rejections
289+
// The error has already been logged and setFailed has been called
290+
process.exit(1);
291+
}
295292
}
296293

297294
// Only run if this file is executed directly (not imported)

0 commit comments

Comments
 (0)