@testomatio/reporter 1.6.0-beta-2-artifacts → 2.0.0-beta-esm

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.
Files changed (97) hide show
  1. package/lib/adapter/codecept.js +288 -330
  2. package/lib/adapter/cucumber/current.js +195 -203
  3. package/lib/adapter/cucumber/legacy.js +130 -155
  4. package/lib/adapter/cucumber.js +5 -16
  5. package/lib/adapter/cypress-plugin/index.js +91 -105
  6. package/lib/adapter/jasmine/jasmine.js +63 -0
  7. package/lib/adapter/jasmine.js +54 -53
  8. package/lib/adapter/jest.js +97 -99
  9. package/lib/adapter/mocha/mocha.js +125 -0
  10. package/lib/adapter/mocha.js +111 -140
  11. package/lib/adapter/playwright.js +168 -200
  12. package/lib/adapter/vitest.js +144 -143
  13. package/lib/adapter/webdriver.js +113 -97
  14. package/lib/bin/reportXml.js +49 -49
  15. package/lib/bin/startTest.js +80 -97
  16. package/lib/client.js +344 -385
  17. package/lib/config.js +16 -21
  18. package/lib/constants.js +49 -43
  19. package/lib/data-storage.js +206 -188
  20. package/lib/fileUploader.js +245 -0
  21. package/lib/junit-adapter/adapter.js +17 -20
  22. package/lib/junit-adapter/csharp.js +18 -14
  23. package/lib/junit-adapter/index.js +27 -25
  24. package/lib/junit-adapter/java.js +41 -53
  25. package/lib/junit-adapter/javascript.js +30 -27
  26. package/lib/junit-adapter/python.js +38 -37
  27. package/lib/junit-adapter/ruby.js +11 -8
  28. package/lib/output.js +44 -52
  29. package/lib/package.json +1 -0
  30. package/lib/pipe/bitbucket.js +208 -227
  31. package/lib/pipe/csv.js +111 -124
  32. package/lib/pipe/github.js +184 -211
  33. package/lib/pipe/gitlab.js +164 -205
  34. package/lib/pipe/html.js +253 -312
  35. package/lib/pipe/index.js +83 -63
  36. package/lib/pipe/testomatio.js +391 -454
  37. package/lib/reporter-functions.js +16 -20
  38. package/lib/reporter.js +47 -17
  39. package/lib/services/artifacts.js +55 -51
  40. package/lib/services/index.js +14 -12
  41. package/lib/services/key-values.js +56 -53
  42. package/lib/services/logger.js +227 -245
  43. package/lib/utils/chalk.js +10 -0
  44. package/lib/utils/pipe_utils.js +91 -84
  45. package/lib/utils/utils.js +289 -273
  46. package/lib/xmlReader.js +480 -519
  47. package/package.json +57 -19
  48. package/src/adapter/codecept.js +369 -0
  49. package/src/adapter/cucumber/current.js +228 -0
  50. package/src/adapter/cucumber/legacy.js +158 -0
  51. package/src/adapter/cucumber.js +4 -0
  52. package/src/adapter/cypress-plugin/index.js +110 -0
  53. package/src/adapter/jasmine.js +60 -0
  54. package/src/adapter/jest.js +107 -0
  55. package/src/adapter/mocha.cjs +2 -0
  56. package/src/adapter/mocha.js +156 -0
  57. package/src/adapter/playwright.js +222 -0
  58. package/src/adapter/vitest.js +183 -0
  59. package/src/adapter/webdriver.js +111 -0
  60. package/src/bin/reportXml.js +67 -0
  61. package/src/bin/startTest.js +119 -0
  62. package/src/client.js +423 -0
  63. package/src/config.js +30 -0
  64. package/src/constants.js +49 -0
  65. package/src/data-storage.js +204 -0
  66. package/src/fileUploader.js +307 -0
  67. package/src/junit-adapter/adapter.js +23 -0
  68. package/src/junit-adapter/csharp.js +16 -0
  69. package/src/junit-adapter/index.js +28 -0
  70. package/src/junit-adapter/java.js +58 -0
  71. package/src/junit-adapter/javascript.js +31 -0
  72. package/src/junit-adapter/python.js +42 -0
  73. package/src/junit-adapter/ruby.js +10 -0
  74. package/src/output.js +57 -0
  75. package/src/pipe/bitbucket.js +254 -0
  76. package/src/pipe/csv.js +140 -0
  77. package/src/pipe/github.js +234 -0
  78. package/src/pipe/gitlab.js +229 -0
  79. package/src/pipe/html.js +366 -0
  80. package/src/pipe/index.js +73 -0
  81. package/src/pipe/testomatio.js +498 -0
  82. package/src/reporter-functions.js +44 -0
  83. package/src/reporter.cjs +22 -0
  84. package/src/reporter.js +24 -0
  85. package/src/services/artifacts.js +59 -0
  86. package/src/services/index.js +13 -0
  87. package/src/services/key-values.js +59 -0
  88. package/src/services/logger.js +314 -0
  89. package/src/template/emptyData.svg +23 -0
  90. package/src/template/testomatio.hbs +1421 -0
  91. package/src/utils/chalk.js +13 -0
  92. package/src/utils/pipe_utils.js +127 -0
  93. package/src/utils/utils.js +341 -0
  94. package/src/xmlReader.js +551 -0
  95. package/lib/bin/cli.js +0 -216
  96. package/lib/bin/uploadArtifacts.js +0 -86
  97. package/lib/uploader.js +0 -312
package/lib/bin/cli.js DELETED
@@ -1,216 +0,0 @@
1
- #!/usr/bin/env node
2
- const { program } = require('commander');
3
- const spawn = require('cross-spawn');
4
- const chalk = require('chalk');
5
- const glob = require('glob');
6
- const debug = require('debug')('@testomatio/reporter:cli');
7
- const TestomatClient = require('../client');
8
- const XmlReader = require('../xmlReader');
9
- const { APP_PREFIX, STATUS } = require('../constants');
10
- const { version } = require('../../package.json');
11
- const config = require('../config');
12
-
13
- console.log(chalk.cyan.bold(` 🤩 Testomat.io Reporter v${version}`));
14
-
15
- program
16
- .version(version)
17
- .option('--env-file <envfile>', 'Load environment variables from env file')
18
- .hook('preAction', (thisCommand) => {
19
- const opts = thisCommand.opts();
20
- if (opts.envFile) {
21
- require('dotenv').config({ path: opts.envFile });
22
- } else {
23
- require('dotenv').config();
24
- }
25
- });
26
-
27
- program
28
- .command('start')
29
- .description('Start a new run and return its ID')
30
- .action(async () => {
31
- console.log('Starting a new Run on Testomat.io...');
32
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
33
- const client = new TestomatClient({ apiKey });
34
-
35
- client.createRun().then(() => {
36
- console.log(process.env.runId);
37
- process.exit(0);
38
- });
39
- });
40
-
41
- program
42
- .command('finish')
43
- .description('Finish Run by its ID')
44
- .action(async () => {
45
- if (!process.env.TESTOMATIO_RUN) {
46
- console.log('TESTOMATIO_RUN environment variable must be set.');
47
- return process.exit(1);
48
- }
49
-
50
- console.log('Finishing Run on Testomat.io...');
51
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
52
- const client = new TestomatClient({ apiKey });
53
-
54
- client.updateRunStatus(STATUS.FINISHED).then(() => {
55
- console.log(chalk.yellow(`Run ${process.env.TESTOMATIO_RUN} was finished`));
56
- process.exit(0);
57
- });
58
- });
59
-
60
- program
61
- .command('run')
62
- .description('Run tests with the specified command')
63
- .argument('<command>', 'Test runner command')
64
- .option('--filter <filter>', 'Additional execution filter')
65
- .action(async (command, opts) => {
66
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
67
- const title = process.env.TESTOMATIO_TITLE;
68
-
69
- if (!command || !command.split) {
70
- console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
71
- return process.exit(255);
72
- }
73
-
74
- const client = new TestomatClient({ apiKey, title, parallel: true });
75
-
76
- if (opts.filter) {
77
- const [pipe, ...optsArray] = opts.filter.split(':');
78
- const pipeOptions = optsArray.join(':');
79
-
80
- try {
81
- const tests = await client.prepareRun({ pipe, pipeOptions });
82
- if (tests && tests.length > 0) {
83
- command += ` --grep (${tests.join('|')})`;
84
- }
85
- } catch (err) {
86
- console.log(APP_PREFIX, err);
87
- }
88
- }
89
-
90
- console.log(APP_PREFIX, `🚀 Running`, chalk.green(command));
91
-
92
- const runTests = () => {
93
- const testCmds = command.split(' ');
94
- const cmd = spawn(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
95
-
96
- cmd.on('close', code => {
97
- const emoji = code === 0 ? '🟢' : '🔴';
98
- console.log(APP_PREFIX, emoji, `Runner exited with ${chalk.bold(code)}`);
99
- if (apiKey) {
100
- const status = code === 0 ? 'passed' : 'failed';
101
- client.updateRunStatus(status, true);
102
- }
103
- process.exit(code);
104
- });
105
- };
106
-
107
- if (apiKey) {
108
- client.createRun().then(runTests);
109
- } else {
110
- runTests();
111
- }
112
- });
113
-
114
- program
115
- .command('xml')
116
- .description('Parse XML reports and upload to Testomat.io')
117
- .argument('<pattern>', 'XML file pattern')
118
- .option('-d, --dir <dir>', 'Project directory')
119
- .option('--java-tests [java-path]', 'Load Java tests from path, by default: src/test/java')
120
- .option('--lang <lang>', 'Language used (python, ruby, java)')
121
- .option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
122
- .action(async (pattern, opts) => {
123
- if (!pattern.endsWith('.xml')) {
124
- pattern += '.xml';
125
- }
126
- let { javaTests, lang } = opts;
127
- if (javaTests === true) javaTests = 'src/test/java';
128
- lang = lang?.toLowerCase();
129
- const runReader = new XmlReader({ javaTests, lang });
130
- const files = glob.sync(pattern, { cwd: opts.dir || process.cwd() });
131
- if (!files.length) {
132
- console.log(APP_PREFIX, `Report can't be created. No XML files found 😥`);
133
- process.exit(1);
134
- }
135
-
136
- for (const file of files) {
137
- console.log(APP_PREFIX, `Parsed ${file}`);
138
- runReader.parse(file);
139
- }
140
-
141
- let timeoutTimer;
142
- if (opts.timelimit) {
143
- timeoutTimer = setTimeout(() => {
144
- console.log(`⚠️ Reached timeout of ${opts.timelimit}s. Exiting... (Exit code is 0 to not fail the pipeline)`);
145
- process.exit(0);
146
- }, parseInt(opts.timelimit, 10) * 1000);
147
- }
148
-
149
- try {
150
- await runReader.createRun();
151
- await runReader.uploadData();
152
- } catch (err) {
153
- console.log(APP_PREFIX, 'Error updating status, skipping...', err);
154
- }
155
-
156
- if (timeoutTimer) clearTimeout(timeoutTimer);
157
- });
158
-
159
- program
160
- .command('upload-artifacts')
161
- .description('Upload artifacts to Testomat.io')
162
- .option('--force', 'Re-upload artifacts even if they were uploaded before')
163
- .action(async (opts) => {
164
- const apiKey = config.TESTOMATIO;
165
-
166
- process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
167
-
168
- const client = new TestomatClient({
169
- apiKey,
170
- isBatchEnabled: false,
171
- });
172
-
173
- let testruns = client.uploader.readUploadedFiles(process.env.TESTOMATIO_RUN);
174
- const numTotalArtifacts = testruns.length;
175
-
176
- debug('Found testruns:', testruns);
177
-
178
- if (!opts.force) testruns = testruns.filter(tr => !tr.uploaded);
179
-
180
- if (!testruns.length) {
181
- console.log(APP_PREFIX, 'Total artifacts:', numTotalArtifacts);
182
- if (numTotalArtifacts) {
183
- console.log(APP_PREFIX, 'No new artifacts to upload');
184
- console.log(APP_PREFIX, 'To re-upload artifacts run this command with --force flag');
185
- }
186
- process.exit(0);
187
- }
188
-
189
- const testrunsByRid = testruns.reduce((acc, { rid, file }) => {
190
- if (!acc[rid]) {
191
- acc[rid] = [];
192
- }
193
- if (!acc[rid].includes(file)) acc[rid].push(file);
194
- return acc;
195
- }, {});
196
-
197
- await client.createRun();
198
- client.uploader.checkEnabled();
199
- client.uploader.disbleLogStorage();
200
-
201
- for (const rid in testrunsByRid) {
202
- const files = testrunsByRid[rid];
203
- await client.addTestRun(undefined, { rid, files });
204
- }
205
-
206
- console.log(APP_PREFIX, client.uploader.totalUploaded, 'artifacts uploaded');
207
- if (client.uploader.failedUpload) {
208
- console.log(APP_PREFIX, client.uploader.failedUpload, 'artifacts failed to upload');
209
- }
210
- });
211
-
212
- program.parse(process.argv);
213
-
214
- if (!process.argv.slice(2).length) {
215
- program.outputHelp();
216
- }
@@ -1,86 +0,0 @@
1
- #!/usr/bin/env node
2
- const program = require('commander');
3
- const chalk = require('chalk');
4
- const debug = require('debug')('@testomatio/reporter:upload-cli');
5
- const TestomatClient = require('../client');
6
- const { APP_PREFIX } = require('../constants');
7
- const { version } = require('../../package.json');
8
- const config = require('../config');
9
-
10
- console.log(chalk.cyan.bold(` 🤩 Testomat.io Reporter v${version}`));
11
-
12
- program
13
- .option('--env-file <envfile>', 'Load environment variables from env file')
14
- .option('--force', 'Re-upload artifacts even if they were uploaded before')
15
- .action(async opts => {
16
-
17
- if (opts.envFile) {
18
- require('dotenv').config(opts.envFile); // eslint-disable-line
19
- } else {
20
- // try to load from env file
21
- require('dotenv').config(); // eslint-disable-line
22
- }
23
-
24
- const apiKey = config.TESTOMATIO;
25
-
26
- process.env.TESTOMATIO_DISABLE_ARTIFACTS = '';
27
- // process.env.TESTOMATIO_ARTIFACTS_SIZE = null;
28
-
29
- const client = new TestomatClient({
30
- apiKey,
31
- isBatchEnabled: false,
32
- });
33
-
34
- let testruns = client.uploader.readUploadedFiles(process.env.TESTOMATIO_RUN);
35
-
36
- const numTotalArtifacts = testruns.length;
37
-
38
- debug('Found testruns:', testruns);
39
-
40
- if (!opts.force) testruns = testruns.filter(tr => !tr.uploaded);
41
-
42
- if (!testruns.length) {
43
- console.log(APP_PREFIX, 'Total artifacts:', numTotalArtifacts);
44
- if (numTotalArtifacts) {
45
- console.log(APP_PREFIX, 'No new artifacts to upload');
46
- console.log(APP_PREFIX, 'To re-upload artifacts run this command with --force flag');
47
- }
48
- process.exit(0);
49
- }
50
-
51
- const testrunsByRid = testruns.reduce((acc, { rid, file }) => {
52
- if (!acc[rid]) {
53
- acc[rid] = [];
54
- }
55
- if (!acc[rid].includes(file)) acc[rid].push(file);
56
- return acc;
57
- }, {});
58
-
59
- let numArtifacts = 0;
60
-
61
- // we need to obtain S3 credentials
62
- await client.createRun();
63
-
64
- client.uploader.checkEnabled();
65
- client.uploader.disbleLogStorage();
66
-
67
- for (const rid in testrunsByRid) {
68
- const files = testrunsByRid[rid];
69
- numArtifacts += files.length;
70
- await client.addTestRun(undefined, {
71
- rid,
72
- files,
73
- });
74
- }
75
-
76
- console.log(APP_PREFIX, client.uploader.totalUploaded, 'artifacts uploaded');
77
- if (client.uploader.failedUpload) {
78
- console.log(APP_PREFIX, client.uploader.failedUpload, 'artifacts failed to upload');
79
- }
80
- });
81
-
82
- if (process.argv.length <= 1) {
83
- program.outputHelp();
84
- }
85
-
86
- program.parse(process.argv);
package/lib/uploader.js DELETED
@@ -1,312 +0,0 @@
1
- const debug = require('debug')('@testomatio/reporter:uploader');
2
- const { S3 } = require('@aws-sdk/client-s3');
3
- const { Upload } = require('@aws-sdk/lib-storage');
4
- const fs = require('fs');
5
- const os = require('os');
6
- const path = require('path');
7
- const promiseRetry = require('promise-retry');
8
- const chalk = require('chalk');
9
- const { APP_PREFIX } = require('./constants');
10
-
11
- class S3Uploader {
12
- constructor() {
13
- this.isEnabled = undefined;
14
- this.storeEnabled = true;
15
- this.config = undefined;
16
-
17
- // counters
18
- this.skippedUpload = 0;
19
- this.failedUpload = 0;
20
- this.totalUploaded = 0;
21
-
22
- this.succesfulUploads = {};
23
-
24
- this.configKeys = [
25
- 'S3_ENDPOINT',
26
- 'S3_REGION',
27
- 'S3_BUCKET',
28
- 'S3_ACCESS_KEY_ID',
29
- 'S3_SECRET_ACCESS_KEY',
30
- 'S3_SESSION_TOKEN',
31
- 'S3_FORCE_PATH_STYLE',
32
- 'TESTOMATIO_DISABLE_ARTIFACTS',
33
- 'TESTOMATIO_PRIVATE_ARTIFACTS',
34
- 'TESTOMATIO_ARTIFACTS_SIZE'
35
- ];
36
- }
37
-
38
- resetConfig() {
39
- this.config = undefined;
40
- this.isEnabled = undefined;
41
- }
42
-
43
- getConfig() {
44
- if (this.config) return this.config;
45
- this.config = this.configKeys.reduce((acc, key) => {
46
- acc[key] = process.env[key];
47
- return acc;
48
- }, {});
49
- return this.config;
50
- }
51
-
52
- getMaskedConfig() {
53
- return Object.fromEntries(
54
- Object.entries(this.getConfig()).map(([key, value]) => [
55
- key,
56
- key === 'S3_SECRET_ACCESS_KEY' || key === 'S3_ACCESS_KEY_ID' ? '***' : value,
57
- ]),
58
- );
59
- }
60
-
61
- checkEnabled() {
62
- if (this.isEnabled !== undefined) return this.isEnabled;
63
-
64
- const { S3_BUCKET, TESTOMATIO_DISABLE_ARTIFACTS } = this.getConfig();
65
- if (!S3_BUCKET) debug(`Upload is disabled because S3_BUCKET is not set`);
66
- this.isEnabled = !!(S3_BUCKET && !TESTOMATIO_DISABLE_ARTIFACTS);
67
-
68
- if (this.isEnabled) debug('S3 uploader is enabled');
69
- debug(this.getMaskedConfig());
70
-
71
- return this.isEnabled;
72
- }
73
-
74
- enableLogStorage() {
75
- this.storeEnabled = true;
76
- }
77
-
78
- disbleLogStorage() {
79
- this.storeEnabled = false;
80
- }
81
-
82
- async uploadToS3(Body, Key) {
83
- const { S3_BUCKET, TESTOMATIO_PRIVATE_ARTIFACTS } = this.getConfig();
84
- const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
85
-
86
- if (!S3_BUCKET || !Body) {
87
- console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), this.getMaskedConfig());
88
- return;
89
- }
90
-
91
- debug('Uploading to S3:', Key);
92
-
93
- const s3 = new S3(this.getS3Config());
94
-
95
- try {
96
- const upload = new Upload({
97
- client: s3,
98
- params: {
99
- Bucket: S3_BUCKET,
100
- Key,
101
- Body,
102
- ACL,
103
- },
104
- });
105
-
106
- const link = await this.getS3LocationLink(upload);
107
- this.totalUploaded++;
108
- this.succesfulUploads[Key] = link;
109
- return link;
110
- } catch (e) {
111
- this.failedUpload++;
112
- debug('S3 uploading error:', e);
113
- console.log(APP_PREFIX, "Upload failed:", e.message, this.getMaskedConfig());
114
- }
115
- }
116
-
117
- readUploadedFiles(runId = null) {
118
- const tempFilePath = this.#getUploadFilePath(runId);
119
-
120
- debug('Reading file', tempFilePath);
121
-
122
- if (!fs.existsSync(tempFilePath)) {
123
- debug('File not found:', tempFilePath);
124
- return [];
125
- }
126
-
127
- const stats = fs.statSync(tempFilePath);
128
- const diff = (+new Date()) - (+stats.mtime);
129
- const diffHours = diff / 1000 / 60 / 60;
130
- if (diffHours > 3) {
131
- console.log(APP_PREFIX, 'Artifacts file is too old, can\'t process artifacts. Please re-run the tests.');
132
- return [];
133
- }
134
-
135
- const data = fs.readFileSync(tempFilePath, 'utf8');
136
- const lines = data.split('\n').filter(Boolean);
137
- return lines.map(line => JSON.parse(line));
138
- }
139
-
140
- #getUploadFilePath(runId = null, forceCreate = false) {
141
- if (!runId && !forceCreate) {
142
- return path.join(os.tmpdir(), 'testomatio.run.latest.jsonl');
143
- }
144
-
145
- const tempFilePath = path.join(os.tmpdir(), `testomatio.run.${runId}.jsonl`);
146
- if (!fs.existsSync(tempFilePath) || forceCreate) {
147
- debug('Creating artifacts file:', tempFilePath);
148
- fs.writeFileSync(tempFilePath, '');
149
- // make symlink to 'testomatio.run.latest.jsonl' file
150
- const latestFilePath = path.join(os.tmpdir(), 'testomatio.run.latest.jsonl');
151
- if (fs.existsSync(latestFilePath)) {
152
- fs.unlinkSync(latestFilePath);
153
- }
154
- fs.symlinkSync(tempFilePath, latestFilePath);
155
-
156
- }
157
- return tempFilePath;
158
- }
159
-
160
- storeUploadedFile(filePath, runId, rid, uploaded = false) {
161
- if (!this.storeEnabled) return;
162
-
163
- if (!filePath || !runId || !rid ) return;
164
-
165
- const tempFilePath = this.#getUploadFilePath(runId);
166
-
167
- const data = { rid, file: filePath, uploaded };
168
- const jsonLine = JSON.stringify(data) + '\n';
169
-
170
- fs.appendFileSync(tempFilePath, jsonLine);
171
- }
172
-
173
- getskippedUpload() {
174
- return this.skippedUpload;
175
- }
176
-
177
- async uploadFileByPath(filePath, pathInS3) {
178
- const [runId, rid] = pathInS3;
179
-
180
- if (!this.isEnabled) {
181
- this.storeUploadedFile(filePath, runId, rid, false);
182
- this.skippedUpload++;
183
- return;
184
- }
185
-
186
- const {
187
- S3_BUCKET,
188
- TESTOMATIO_ARTIFACTS_SIZE,
189
- } = this.getConfig();
190
-
191
- debug('Started upload', filePath, 'to', S3_BUCKET);
192
-
193
- const isFileExist = await this.checkFileExists(filePath, 20, 500);
194
-
195
- if (!isFileExist) {
196
- this.failedUpload++;
197
- console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
198
- return;
199
- }
200
-
201
- const fileSize = fs.statSync(filePath).size;
202
- const fileSizeInMb = fileSize / (1024 * 1024);
203
-
204
- if (TESTOMATIO_ARTIFACTS_SIZE && fileSizeInMb > parseInt(TESTOMATIO_ARTIFACTS_SIZE)) {
205
- this.skippedUpload++;
206
- console.error(chalk.yellow(`Artifacts file ${filePath} exceeds the maximum allowed size. Skipping...`));
207
- return;
208
- }
209
- debug('File:', filePath, 'exists, size:', fileSizeInMb.toFixed(2), 'MB');
210
-
211
- const fileStream = fs.createReadStream(filePath);
212
- const Key = pathInS3.join('/');
213
-
214
- const link = await this.uploadToS3(fileStream, Key);
215
-
216
- this.storeUploadedFile(filePath, runId, rid, !!link);
217
-
218
- return link;
219
- }
220
-
221
- async uploadFileAsBuffer(buffer, pathInS3) {
222
- if (!this.isEnabled) return;
223
-
224
- let Key = pathInS3.join('/');
225
- const ext = this.#getFileExtBase64(buffer);
226
-
227
- if (ext) {
228
- Key = `${Key}.${ext}`;
229
- }
230
-
231
- return this.uploadToS3(buffer, Key);
232
- }
233
-
234
- async checkFileExists(filePath, attempts = 5, intervalMs = 500) {
235
- return promiseRetry(
236
- async (retry, number) => {
237
- try {
238
- fs.accessSync(filePath);
239
- return true;
240
- } catch (err) {
241
- if (number === attempts) {
242
- return false;
243
- }
244
- debug(`File not found, retrying (attempt ${number}/${attempts})`);
245
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
246
- retry(err);
247
- }
248
- },
249
- {
250
- retries: attempts,
251
- minTimeout: intervalMs,
252
- maxTimeout: intervalMs,
253
- }
254
- );
255
- }
256
-
257
- async getS3LocationLink(out) {
258
- const response = await out.done();
259
-
260
- let s3Location = response?.Location;
261
-
262
- if (!s3Location) {
263
- s3Location = out?.singleUploadResult?.Location;
264
- debug('Uploaded singleUploadResult.Location', s3Location);
265
-
266
- if (!s3Location) {
267
- throw new Error("Problems getting the S3 artifact's link. Please check S3 permissions!");
268
- }
269
- }
270
-
271
- return s3Location;
272
- }
273
-
274
- #getFileExtBase64(str) {
275
- const type = str.charAt(0);
276
-
277
- return (
278
- {
279
- '/': 'jpg',
280
- i: 'png',
281
- R: 'gif',
282
- U: 'webp',
283
- }[type] || ''
284
- );
285
- }
286
-
287
- getS3Config() {
288
- const { S3_REGION, S3_SESSION_TOKEN, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE, S3_ENDPOINT } =
289
- this.getConfig();
290
-
291
- const cfg = {
292
- region: S3_REGION,
293
- credentials: {
294
- accessKeyId: S3_ACCESS_KEY_ID,
295
- secretAccessKey: S3_SECRET_ACCESS_KEY,
296
- s3ForcePathStyle: S3_FORCE_PATH_STYLE,
297
- },
298
- };
299
-
300
- if (S3_SESSION_TOKEN) {
301
- cfg.credentials.sessionToken = S3_SESSION_TOKEN;
302
- }
303
-
304
- if (S3_ENDPOINT) {
305
- cfg.endpoint = S3_ENDPOINT;
306
- }
307
-
308
- return cfg;
309
- }
310
- }
311
-
312
- module.exports = S3Uploader;