Skip to content

Commit 8ba4679

Browse files
authored
Upgrade Axios to v1 (#25)
* upgrade axios to v1 * add try/catch blocks * remove node 10x * update node support matrix
1 parent bbade79 commit 8ba4679

5 files changed

Lines changed: 117 additions & 45 deletions

File tree

.github/workflows/node.js.yml

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,33 @@ name: Node.js CI
55

66
on:
77
push:
8-
branches: [ master ]
8+
branches: [master]
99
pull_request:
10-
branches: [ master ]
10+
branches: [master]
1111

1212
jobs:
1313
build:
14-
1514
runs-on: ubuntu-latest
1615

1716
strategy:
1817
matrix:
19-
node-version: [10.x, 12.x, 14.x]
18+
include:
19+
- node: 18
20+
npm: ^9
21+
- node: 20
22+
npm: ^10
23+
- node: 22
24+
npm: ^10
25+
- node: 24
26+
npm: ^11
27+
- node: latest
28+
npm: latest
2029

2130
steps:
22-
- uses: actions/checkout@v2
23-
- name: Use Node.js ${{ matrix.node-version }}
24-
uses: actions/setup-node@v1
25-
with:
26-
node-version: ${{ matrix.node-version }}
27-
- run: npm install
28-
- run: npm test
31+
- uses: actions/checkout@v2
32+
- name: Use Node.js ${{ matrix.node-version }}
33+
uses: actions/setup-node@v1
34+
with:
35+
node-version: ${{ matrix.node-version }}
36+
- run: npm install
37+
- run: npm test

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"dependencies": {
1313
"adm-zip": "^0.5.2",
14-
"axios": "^0.24.0",
14+
"axios": "1.14.0",
1515
"chalk": "^4.1.0",
1616
"form-data": "^3.0.0",
1717
"glob": "^7.1.6",

src/common/rollbar-api.js

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
'use strict';
22

3+
// Helper to normalize axios error/response for consistent error handling
4+
function normalizeAxiosError(resp) {
5+
if (!resp) return { statusText: 'Axios Error', message: 'Unknown error' };
6+
if (resp.status === 200) return null;
7+
if (typeof resp.data === 'string') {
8+
return { statusText: resp.statusText || 'Axios Error', message: resp.data };
9+
}
10+
if (typeof resp.data === 'object' && resp.data !== null) {
11+
return Object.assign({}, resp.data, { statusText: resp.statusText || 'Axios Error' });
12+
}
13+
return { statusText: resp.statusText || 'Axios Error', message: String(resp.data) };
14+
}
15+
316
const axios = require('axios');
417
const FormData = require('form-data');
518

@@ -21,44 +34,57 @@ class RollbarAPI {
2134

2235
async deploy(request, deployId) {
2336
let resp;
24-
if(deployId) {
25-
output.verbose('', 'Update to an existing deploy with deploy_id: ' + deployId);
26-
resp = await this.axios.patch('/deploy/' + deployId, request);
27-
} else {
28-
output.verbose('','deploy_id not present so likely a new deploy');
29-
resp = await this.axios.post('/deploy', request);
30-
}
37+
try {
38+
if(deployId) {
39+
output.verbose('', 'Update to an existing deploy with deploy_id: ' + deployId);
40+
resp = await this.axios.patch('/deploy/' + deployId, request);
41+
} else {
42+
output.verbose('','deploy_id not present so likely a new deploy');
43+
resp = await this.axios.post('/deploy', request);
44+
}
3145

32-
// Output deploy-id
33-
if (resp.status === 200) {
34-
output.success('', resp.data.data);
46+
// Output deploy-id
47+
if (resp.status === 200) {
48+
output.success('', resp.data.data);
49+
}
50+
return this.processResponse(resp);
51+
} catch (error) {
52+
output.verbose('', 'axios threw error:', error);
53+
return this.processResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
3554
}
36-
return this.processResponse(resp);
3755
}
3856

3957
async sigendURLsourcemaps(request) {
40-
41-
const resp = await this.axios.post(
42-
'/signed_url/sourcemap_bundle', { version: request.version , prefix_url: request.baseUrl}
43-
);
44-
return this.processSignedURLResponse(resp);
58+
try {
59+
const resp = await this.axios.post(
60+
'/signed_url/sourcemap_bundle', { version: request.version , prefix_url: request.baseUrl}
61+
);
62+
return this.processSignedURLResponse(resp);
63+
} catch (error) {
64+
output.verbose('', 'axios threw error:', error);
65+
return this.processSignedURLResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
66+
}
4567
}
4668

4769
async sourcemaps(request) {
4870
output.verbose('', 'minified_url: ' + request.minified_url);
4971

5072
const form = this.convertRequestToForm(request);
51-
const resp = await this.axios.post(
52-
'/sourcemap',
53-
form.getBuffer(), // use buffer to prevent unwanted string escaping.
54-
{ headers: {
55-
// axios needs some help with headers for form data.
56-
'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`,
57-
'Content-Length': form.getLengthSync()
58-
}}
59-
);
60-
61-
return this.processResponse(resp);
73+
try {
74+
const resp = await this.axios.post(
75+
'/sourcemap',
76+
form.getBuffer(), // use buffer to prevent unwanted string escaping.
77+
{ headers: {
78+
// axios needs some help with headers for form data.
79+
'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`,
80+
'Content-Length': form.getLengthSync()
81+
}}
82+
);
83+
return this.processResponse(resp);
84+
} catch (error) {
85+
output.verbose('', 'axios threw error:', error);
86+
return this.processResponse(error.response || { data: error.message, status: error.status || 500, statusText: error.statusText || 'Axios Error' });
87+
}
6288
}
6389

6490
convertRequestToForm(request) {
@@ -80,15 +106,15 @@ class RollbarAPI {
80106

81107
processSignedURLResponse(resp) {
82108
output.verbose('', 'response:', resp.data, resp.status, resp.statusText);
83-
return resp.data;
109+
if (resp.status === 200) {
110+
return resp.data;
111+
}
112+
return normalizeAxiosError(resp);
84113
}
85114

86115
processResponse(resp) {
87116
output.verbose('', 'response:', resp.data, resp.status, resp.statusText);
88-
if (resp.status === 200) {
89-
return null;
90-
}
91-
return resp.data;
117+
return normalizeAxiosError(resp);
92118
}
93119
}
94120

test/common/rollbar-api.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,40 @@ describe('.deploy() with deployId', function() {
285285
});
286286
});
287287

288+
describe('RollbarAPI error handling (catch coverage)', function() {
289+
beforeEach(function() {
290+
const accessToken = 'abcd';
291+
this.rollbarAPI = new RollbarAPI(accessToken);
292+
global.output = new Output({verbose: false});
293+
});
294+
295+
afterEach(function() {
296+
global.output = null;
297+
});
298+
299+
it('should handle axios throwing in deploy()', async function() {
300+
// Force axios.patch to reject
301+
const stub = sinon.stub(this.rollbarAPI.axios, 'patch').rejects(new Error('Network error'));
302+
const response = await this.rollbarAPI.deploy({}, '123');
303+
expect(response).to.be.a('object');
304+
expect(response.statusText).to.equal('Axios Error');
305+
stub.restore();
306+
});
307+
308+
it('should handle axios throwing in sigendURLsourcemaps()', async function() {
309+
const stub = sinon.stub(this.rollbarAPI.axios, 'post').rejects(new Error('Network error'));
310+
const response = await this.rollbarAPI.sigendURLsourcemaps({ version: '1', baseUrl: 'https://example.com/' });
311+
expect(response).to.be.a('object');
312+
expect(response.statusText).to.equal('Axios Error');
313+
stub.restore();
314+
});
315+
316+
it('should handle axios throwing in sourcemaps()', async function() {
317+
const stub = sinon.stub(this.rollbarAPI.axios, 'post').rejects(new Error('Network error'));
318+
const response = await this.rollbarAPI.sourcemaps({ version: '1', minified_url: 'https://example.com/', source_map: 'abc' });
319+
expect(response).to.be.a('object');
320+
expect(response.statusText).to.equal('Axios Error');
321+
stub.restore();
322+
});
323+
});
324+

test/sourcemaps/scanner.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe('.scan()', function() {
139139
await scanner.scan();
140140
const files = scanner.mappedFiles();
141141

142-
expect(files[0].errors[0].error).to.have.string('Error parsing map file: Unexpected token $ in JSON at position 24');
142+
expect(files[0].errors[0].error).to.have.string('Error parsing map file:');
143143
expect(files[1].errors[0].error).to.have.string('Error parsing map file: "sources" is a required argument');
144144
});
145145
});

0 commit comments

Comments
 (0)