@testomatio/reporter 2.6.3 → 2.6.4-beta-acl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -264,6 +264,8 @@ class TestomatioPipe {
264
264
  const errorText = err.response?.data?.message || err.message;
265
265
  debug('Error creating run', err);
266
266
  console.log(errorText || err);
267
+ if (err.response?.status === 403)
268
+ this.#disablePipe();
267
269
  if (!this.apiKey)
268
270
  console.error('Testomat.io API key is not set');
269
271
  if (!this.apiKey?.startsWith('tstmt'))
@@ -312,6 +314,8 @@ class TestomatioPipe {
312
314
  maxContentLength: Infinity,
313
315
  })
314
316
  .catch(err => {
317
+ if (err.response?.status === 403)
318
+ this.#disablePipe();
315
319
  this.requestFailures++;
316
320
  this.notReportedTestsCount++;
317
321
  if (err.response) {
@@ -363,6 +367,8 @@ class TestomatioPipe {
363
367
  maxContentLength: Infinity,
364
368
  })
365
369
  .catch(err => {
370
+ if (err.response?.status === 403)
371
+ this.#disablePipe();
366
372
  this.requestFailures++;
367
373
  this.notReportedTestsCount += testsToSend.length;
368
374
  if (err.response) {
@@ -472,6 +478,17 @@ class TestomatioPipe {
472
478
  }
473
479
  debug('Run finished');
474
480
  }
481
+ #disablePipe() {
482
+ this.isEnabled = false;
483
+ this.apiKey = null;
484
+ // clear interval function, otherwise the proccess will continue indefinitely
485
+ if (this.batch.intervalFunction) {
486
+ clearInterval(this.batch.intervalFunction);
487
+ this.batch.intervalFunction = null;
488
+ this.batch.isEnabled = false;
489
+ }
490
+ this.batch.tests = [];
491
+ }
475
492
  #logFailedResponse(error) {
476
493
  let responseBody = stringify(error.response?.data ?? error.response ?? error, { pretty: true });
477
494
  if (!responseBody)
package/lib/uploader.js CHANGED
@@ -40,6 +40,7 @@ class S3Uploader {
40
40
  'TESTOMATIO_DISABLE_ARTIFACTS',
41
41
  'TESTOMATIO_PRIVATE_ARTIFACTS',
42
42
  'TESTOMATIO_ARTIFACT_MAX_SIZE_MB',
43
+ 'TESTOMATIO_S3_NO_ACL',
43
44
  ];
44
45
  }
45
46
  resetConfig() {
@@ -91,7 +92,7 @@ class S3Uploader {
91
92
  * @returns
92
93
  */
93
94
  async #uploadToS3(Body, Key, file) {
94
- const { S3_BUCKET, TESTOMATIO_PRIVATE_ARTIFACTS } = this.getConfig();
95
+ const { S3_BUCKET, TESTOMATIO_PRIVATE_ARTIFACTS, TESTOMATIO_S3_NO_ACL } = this.getConfig();
95
96
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
96
97
  if (!S3_BUCKET || !Body) {
97
98
  console.log(constants_js_1.APP_PREFIX, picocolors_1.default.bold(picocolors_1.default.red(`Failed uploading '${Key}'. Please check S3 credentials`)), this.getMaskedConfig());
@@ -105,8 +106,10 @@ class S3Uploader {
105
106
  Key,
106
107
  Body,
107
108
  };
108
- // disable ACL for I AM roles
109
- if (!s3Config.credentials.sessionToken) {
109
+ // disable ACL for IAM roles or GCS (GCS doesn't support x-amz-acl header)
110
+ // to precent potential issues, forece setting TESTOMATIO_S3_NO_ACL env var too in such case
111
+ const isGCS = s3Config.endpoint && s3Config.endpoint.includes('storage.googleapis.com');
112
+ if (!s3Config.credentials.sessionToken && !TESTOMATIO_S3_NO_ACL && !isGCS) {
110
113
  params.ACL = ACL;
111
114
  }
112
115
  try {
@@ -119,7 +122,7 @@ class S3Uploader {
119
122
  catch (e) {
120
123
  this.failedUploads.push({ path: file.path, size: file.size });
121
124
  debug('S3 uploading error:', e);
122
- console.log(constants_js_1.APP_PREFIX, 'Upload failed:', e.message, '\nConfig:\n', this.getMaskedConfig());
125
+ console.log(constants_js_1.APP_PREFIX, 'Upload failed:', e.message, `\nFile:\n ${file.path}, size: ${(0, filesize_1.filesize)(file.size || 0)}`, '\nConfig:\n', this.getMaskedConfig());
123
126
  }
124
127
  }
125
128
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.6.3",
3
+ "version": "2.6.4-beta-acl",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -294,6 +294,7 @@ class TestomatioPipe {
294
294
  const errorText = err.response?.data?.message || err.message;
295
295
  debug('Error creating run', err);
296
296
  console.log(errorText || err);
297
+ if (err.response?.status === 403) this.#disablePipe();
297
298
  if (!this.apiKey) console.error('Testomat.io API key is not set');
298
299
  if (!this.apiKey?.startsWith('tstmt')) console.error('Testomat.io API key is invalid');
299
300
 
@@ -347,6 +348,7 @@ class TestomatioPipe {
347
348
  maxContentLength: Infinity,
348
349
  })
349
350
  .catch(err => {
351
+ if (err.response?.status === 403) this.#disablePipe();
350
352
  this.requestFailures++;
351
353
  this.notReportedTestsCount++;
352
354
  if (err.response) {
@@ -397,6 +399,7 @@ class TestomatioPipe {
397
399
  maxContentLength: Infinity,
398
400
  })
399
401
  .catch(err => {
402
+ if (err.response?.status === 403) this.#disablePipe();
400
403
  this.requestFailures++;
401
404
  this.notReportedTestsCount += testsToSend.length;
402
405
  if (err.response) {
@@ -520,6 +523,19 @@ class TestomatioPipe {
520
523
  debug('Run finished');
521
524
  }
522
525
 
526
+ #disablePipe() {
527
+ this.isEnabled = false;
528
+ this.apiKey = null;
529
+
530
+ // clear interval function, otherwise the proccess will continue indefinitely
531
+ if (this.batch.intervalFunction) {
532
+ clearInterval(this.batch.intervalFunction);
533
+ this.batch.intervalFunction = null;
534
+ this.batch.isEnabled = false;
535
+ }
536
+ this.batch.tests = [];
537
+ }
538
+
523
539
  #logFailedResponse(error) {
524
540
  let responseBody = stringify(error.response?.data ?? error.response ?? error, { pretty: true });
525
541
  if (!responseBody) responseBody = '<empty>';
package/src/uploader.js CHANGED
@@ -38,6 +38,7 @@ export class S3Uploader {
38
38
  'TESTOMATIO_DISABLE_ARTIFACTS',
39
39
  'TESTOMATIO_PRIVATE_ARTIFACTS',
40
40
  'TESTOMATIO_ARTIFACT_MAX_SIZE_MB',
41
+ 'TESTOMATIO_S3_NO_ACL',
41
42
  ];
42
43
  }
43
44
 
@@ -97,7 +98,7 @@ export class S3Uploader {
97
98
  * @returns
98
99
  */
99
100
  async #uploadToS3(Body, Key, file) {
100
- const { S3_BUCKET, TESTOMATIO_PRIVATE_ARTIFACTS } = this.getConfig();
101
+ const { S3_BUCKET, TESTOMATIO_PRIVATE_ARTIFACTS, TESTOMATIO_S3_NO_ACL } = this.getConfig();
101
102
  const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
102
103
 
103
104
  if (!S3_BUCKET || !Body) {
@@ -118,14 +119,15 @@ export class S3Uploader {
118
119
  Key,
119
120
  Body,
120
121
  };
121
- // disable ACL for I AM roles
122
- if (!s3Config.credentials.sessionToken) {
122
+ // disable ACL for IAM roles or GCS (GCS doesn't support x-amz-acl header)
123
+ // to precent potential issues, forece setting TESTOMATIO_S3_NO_ACL env var too in such case
124
+ const isGCS = s3Config.endpoint && s3Config.endpoint.includes('storage.googleapis.com');
125
+ if (!s3Config.credentials.sessionToken && !TESTOMATIO_S3_NO_ACL && !isGCS) {
123
126
  params.ACL = ACL;
124
127
  }
125
128
 
126
129
  try {
127
130
  const upload = new Upload({ client: s3, params });
128
-
129
131
  const link = await this.getS3LocationLink(upload);
130
132
  this.successfulUploads.push({ path: file.path, size: file.size, link });
131
133
  debug(`📤 Uploaded artifact. File: ${file.path}, size: ${prettyBytes(file.size || 0)}, link: ${link}`);
@@ -133,7 +135,14 @@ export class S3Uploader {
133
135
  } catch (e) {
134
136
  this.failedUploads.push({ path: file.path, size: file.size });
135
137
  debug('S3 uploading error:', e);
136
- console.log(APP_PREFIX, 'Upload failed:', e.message, '\nConfig:\n', this.getMaskedConfig());
138
+ console.log(
139
+ APP_PREFIX,
140
+ 'Upload failed:',
141
+ e.message,
142
+ `\nFile:\n ${file.path}, size: ${prettyBytes(file.size || 0)}`,
143
+ '\nConfig:\n',
144
+ this.getMaskedConfig(),
145
+ );
137
146
  }
138
147
  }
139
148