@testomatio/reporter 1.2.0-beta-4 → 1.2.0

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.
@@ -3,10 +3,15 @@ const { S3 } = require('@aws-sdk/client-s3');
3
3
  const { Upload } = require('@aws-sdk/lib-storage');
4
4
 
5
5
  const fs = require('fs');
6
+ const util = require('util');
6
7
  const path = require('path');
8
+ const promiseRetry = require('promise-retry');
9
+
10
+ const readFile = util.promisify(fs.readFile);
11
+ const stat = util.promisify(fs.stat);
7
12
  const chalk = require('chalk');
8
13
  const { randomUUID } = require('crypto');
9
- const memoize = require('lodash.memoize');
14
+
10
15
  const { APP_PREFIX } = require('./constants');
11
16
 
12
17
  const keys = [
@@ -93,51 +98,69 @@ const uploadUsingS3 = async (filePath, runId) => {
93
98
  Key = filePath.name;
94
99
  }
95
100
 
96
- if (!fs.existsSync(filePath)) {
97
- console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
98
- return;
99
- }
100
-
101
101
  const {
102
- TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
102
+ TESTOMATIO_PRIVATE_ARTIFACTS,
103
+ S3_BUCKET
103
104
  } = getConfig();
104
105
 
105
- debug('S3 config', getMaskedConfig());
106
- debug('Uploading', filePath, 'to', S3_BUCKET);
107
-
108
- const fileData = fs.readFileSync(filePath);
106
+ try {
107
+ debug('S3 config', getMaskedConfig());
108
+ debug('Started upload', filePath, 'to ', S3_BUCKET);
109
109
 
110
- Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
111
- const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
110
+ // Verification that the file was actually created: 20 attempts of 0.5 second => 10sec
111
+ const isFileExist = await checkFileExists(filePath, 20, 500);
112
112
 
113
- const s3 = new S3(_getS3Config());
113
+ if (!isFileExist) {
114
+ console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
115
+ return;
116
+ }
114
117
 
115
- const params = {
116
- Bucket: S3_BUCKET,
117
- Key,
118
- Body: fileData,
119
- ContentType,
120
- ACL,
121
- };
118
+ debug('File: ', filePath, ' exists');
119
+
120
+ const fileData = await readFile(filePath);
122
121
 
123
- try {
122
+ Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
123
+
124
+ const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
125
+
126
+ if (!S3_BUCKET || !fileData) {
127
+ console.log(
128
+ APP_PREFIX,
129
+ chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), getMaskedConfig());
130
+ return;
131
+ }
132
+
133
+ const s3 = new S3(_getS3Config());
134
+
135
+ const params = {
136
+ Bucket: S3_BUCKET,
137
+ Key,
138
+ Body: fileData,
139
+ ContentType,
140
+ ACL,
141
+ };
142
+
124
143
  const out = new Upload({
125
144
  client: s3,
126
145
  params
127
146
  });
128
147
 
129
- await out.done();
130
- debug('Uploaded', out.singleUploadResult.Location)
131
-
132
- return out.singleUploadResult.Location;
133
- } catch (e) {
134
- console.log(e);
135
- console.log(APP_PREFIX, chalk.red(`Failed uploading '${Key}'. Please check S3 credentials`), getMaskedConfig());
148
+
149
+ const link = await getS3LocationLink(out);
150
+
151
+ debug(`Succesfully uploaded ${filePath} => ${S3_BUCKET}/${Key} | URL: ${link}`);
136
152
 
153
+ return link;
154
+ }
155
+ catch (e) {
156
+ debug('S3 file uploading error: ', e);
157
+
137
158
  console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
159
+
138
160
  if (!TESTOMATIO_PRIVATE_ARTIFACTS) {
139
161
  console.log(APP_PREFIX, `To enable ${chalk.bold('PRIVATE')} uploads set: TESTOMATIO_PRIVATE_ARTIFACTS=1`);
140
- } else {
162
+ }
163
+ else {
141
164
  console.log(
142
165
  APP_PREFIX,
143
166
  `To enable ${chalk.bold('PUBLIC')} uploads remove TESTOMATIO_PRIVATE_ARTIFACTS env variable`,
@@ -148,7 +171,6 @@ const fileData = fs.readFileSync(filePath);
148
171
  };
149
172
 
150
173
  const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
151
-
152
174
  const {
153
175
  S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
154
176
  } = getConfig();
@@ -158,6 +180,18 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
158
180
  const fileExtension = _getFileExtBase64(buffer.toString('base64'));
159
181
  const Key = `${runId}/${fileName}${fileExtension}`;
160
182
 
183
+ if (!S3_BUCKET || !buffer) {
184
+ console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
185
+ accessKeyId: S3_ACCESS_KEY_ID,
186
+ secretAccessKey: S3_SECRET_ACCESS_KEY ? '**** (hidden) ***' : '(empty)',
187
+ region: S3_REGION,
188
+ bucket: S3_BUCKET,
189
+ acl: ACL,
190
+ endpoint: S3_ENDPOINT,
191
+ });
192
+ return;
193
+ }
194
+
161
195
  const s3 = new S3(_getS3Config());
162
196
 
163
197
  try {
@@ -171,20 +205,14 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
171
205
  ACL,
172
206
  }
173
207
  });
174
- await out.done();
175
208
 
176
- return out.singleUploadResult.Location;
177
- } catch (e) {
178
- console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
179
- accessKeyId: S3_ACCESS_KEY_ID,
180
- secretAccessKey: S3_SECRET_ACCESS_KEY ? '**** (hidden) ***' : '(empty)',
181
- region: S3_REGION,
182
- bucket: S3_BUCKET,
183
- acl: ACL,
184
- endpoint: S3_ENDPOINT,
185
- });
209
+ return await getS3LocationLink(out);
210
+ }
211
+ catch (e) {
212
+ debug('S3 buffer uploading error: ', e);
186
213
 
187
214
  console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
215
+
188
216
  if (!TESTOMATIO_PRIVATE_ARTIFACTS) {
189
217
  console.log(APP_PREFIX, `To enable ${chalk.bold('PRIVATE')} uploads set: TESTOMATIO_PRIVATE_ARTIFACTS=1`);
190
218
  } else {
@@ -203,7 +231,9 @@ const uploadFileByPath = async (filePath, runId) => {
203
231
  return uploadUsingS3(filePath, runId);
204
232
  }
205
233
  } catch (e) {
206
- console.error(chalk.red('Error occurred while uploading artifacts'), e);
234
+ debug(e);
235
+
236
+ console.error(chalk.red('Error occurred while uploading artifacts! '), e);
207
237
  }
208
238
  };
209
239
 
@@ -213,13 +243,62 @@ const uploadFileAsBuffer = async (buffer, fileName, runId) => {
213
243
  return uploadUsingS3AsBuffer(buffer, fileName, runId);
214
244
  }
215
245
  } catch (e) {
216
- console.error(chalk.red('Error occurred while uploading artifacts'), e);
246
+ debug(e);
247
+
248
+ console.error(chalk.red('Error occurred while uploading artifacts! '), e);
217
249
  }
218
250
  };
219
251
 
252
+ const checkFileExists = async (filePath, attempts = 5, intervalMs = 500) => {
253
+ const checkFile = async () => {
254
+ const fileStats = await stat(filePath);
255
+ if (fileStats.isFile()) {
256
+ return true;
257
+ }
258
+
259
+ throw new Error('File not found');
260
+ };
261
+
262
+ try {
263
+ await promiseRetry(
264
+ {
265
+ retries: attempts,
266
+ minTimeout: intervalMs
267
+ },
268
+ checkFile
269
+ );
270
+
271
+ return true;
272
+ } catch (err) {
273
+ console.error(
274
+ chalk.yellow(`File ${filePath} was not found or did not have time to be generated...`)
275
+ );
276
+
277
+ return false;
278
+ }
279
+ };
280
+
281
+ const getS3LocationLink = async (out) => {
282
+ const response = await out.done();
283
+
284
+ let s3Location = response?.Location;
285
+
286
+ if (!s3Location) {
287
+ // TODO: out: a fallback case - remove after deeper testing
288
+ s3Location = out?.singleUploadResult?.Location;
289
+ debug('Uploaded singleUploadResult.Location', s3Location);
290
+
291
+ if (!s3Location) {
292
+ throw new Error("Problems getting the S3 artifact's link. Please check S3 permissions!");
293
+ }
294
+ }
295
+
296
+ return s3Location;
297
+ };
298
+
220
299
  module.exports = {
221
- uploadFileByPath: memoize(uploadFileByPath),
222
- uploadFileAsBuffer: memoize(uploadFileAsBuffer),
300
+ uploadFileByPath,
301
+ uploadFileAsBuffer,
223
302
  isArtifactsEnabled,
224
303
  resetConfig,
225
304
  };
@@ -6,8 +6,7 @@ const RubyAdapter = require('./ruby');
6
6
  const CSharpAdapter = require('./csharp');
7
7
 
8
8
  function AdapterFactory(lang, opts) {
9
- if (!lang) return new Adapter(opts);
10
-
9
+
11
10
  if (lang === 'java') {
12
11
  return new JavaAdapter(opts);
13
12
  }
@@ -23,6 +22,8 @@ function AdapterFactory(lang, opts) {
23
22
  if (lang === 'c#' || lang === 'csharp') {
24
23
  return new CSharpAdapter(opts);
25
24
  }
25
+
26
+ return new Adapter(opts);
26
27
  }
27
28
 
28
29
  module.exports = AdapterFactory;
@@ -23,7 +23,7 @@ class GitLabPipe {
23
23
  this.store = store;
24
24
  this.tests = [];
25
25
  // GitLab PAT looks like glpat-nKGdja3jsG4850sGksh7
26
- this.token = params.GITLAB_PAT || this.ENV.GITLAB_PAT;
26
+ this.token = params.GITLAB_PAT || process.env.GITLAB_PAT || this.ENV.GITLAB_PAT;
27
27
  this.hiddenCommentData = `<!--- testomat.io report ${process.env.CI_JOB_NAME || ''} -->`;
28
28
 
29
29
  debug(