@applitools/core 2.5.2 → 2.5.3-legacy

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 (190) hide show
  1. package/dist/abort.js +40 -0
  2. package/dist/automation/abort.js +47 -0
  3. package/dist/automation/close.js +52 -0
  4. package/dist/automation/extract-text.js +3 -2
  5. package/dist/automation/get-nml-client.js +36 -0
  6. package/dist/automation/get-results.js +21 -0
  7. package/dist/automation/get-viewport-size.js +3 -2
  8. package/dist/automation/locate-text.js +3 -2
  9. package/dist/automation/locate.js +3 -2
  10. package/dist/automation/set-viewport-size.js +3 -2
  11. package/dist/automation/types.js +0 -15
  12. package/dist/automation/utils/report-kobiton.js +21 -0
  13. package/dist/automation/utils/take-screenshot.js +4 -2
  14. package/dist/automation/utils/to-base-check-settings.js +69 -7
  15. package/dist/automation/utils/to-environment-key.js +31 -0
  16. package/dist/automation/utils/uniquify-environments.js +27 -0
  17. package/dist/automation/utils/wait-for-lazy-load.js +9 -8
  18. package/dist/autonomous/core.js +25 -0
  19. package/dist/autonomous/create-render-results.js +49 -0
  20. package/dist/autonomous/create-render-target.js +19 -0
  21. package/dist/autonomous/get-render-results.js +55 -0
  22. package/dist/autonomous/open-eyes.js +13 -0
  23. package/dist/autonomous/start-renders.js +67 -0
  24. package/dist/autonomous/take-snapshots.js +16 -0
  25. package/dist/autonomous/types.js +17 -0
  26. package/dist/check-and-close.js +32 -15
  27. package/dist/check.js +33 -30
  28. package/dist/classic/check-and-close.js +189 -46
  29. package/dist/classic/check.js +319 -60
  30. package/dist/classic/core.js +6 -5
  31. package/dist/classic/get-base-eyes.js +27 -7
  32. package/dist/classic/open-eyes.js +47 -57
  33. package/dist/classic/utils/extract-default-environments.js +73 -0
  34. package/dist/classic/utils/take-dom-capture.js +2 -1
  35. package/dist/classic/utils/take-screenshots.js +63 -0
  36. package/dist/cli/cli.js +99 -3
  37. package/dist/close-batch.js +8 -7
  38. package/dist/close.js +32 -4
  39. package/dist/core.js +43 -9
  40. package/dist/delete-test.js +9 -7
  41. package/dist/extract-text.js +9 -5
  42. package/dist/get-account-info.js +36 -0
  43. package/dist/get-ec-client.js +3 -2
  44. package/dist/get-eyes-results.js +29 -3
  45. package/dist/get-manager-results.js +52 -18
  46. package/dist/get-typed-eyes.js +5 -6
  47. package/dist/index.js +3 -3
  48. package/dist/lang.js +31 -0
  49. package/dist/locate-text.js +7 -5
  50. package/dist/locate.js +7 -5
  51. package/dist/make-manager.js +34 -11
  52. package/dist/offline/merge-configs.js +42 -0
  53. package/dist/offline/run-offline-snapshots.js +341 -0
  54. package/dist/open-eyes.js +192 -48
  55. package/dist/run-offline-snapshots.js +336 -0
  56. package/dist/troubleshoot/check-network.js +5 -1
  57. package/dist/troubleshoot/eyes.js +3 -3
  58. package/dist/troubleshoot/logs.js +76 -0
  59. package/dist/troubleshoot/ufg.js +23 -16
  60. package/dist/ufg/check-and-close.js +109 -174
  61. package/dist/ufg/check.js +111 -178
  62. package/dist/ufg/core.js +10 -8
  63. package/dist/ufg/create-render-target-from-snapshot.js +21 -0
  64. package/dist/ufg/get-base-eyes.js +40 -12
  65. package/dist/ufg/get-ufg-client.js +13 -4
  66. package/dist/ufg/open-eyes.js +33 -57
  67. package/dist/ufg/take-snapshots.js +92 -0
  68. package/dist/ufg/utils/extract-default-environment.js +22 -0
  69. package/dist/ufg/utils/generate-safe-selectors.js +9 -32
  70. package/dist/ufg/utils/take-dom-snapshot.js +61 -26
  71. package/dist/ufg/utils/take-dom-snapshots.js +99 -68
  72. package/dist/ufg/utils/to-generated-selectors.js +67 -0
  73. package/dist/ufg/utils/to-safe-check-settings.js +69 -0
  74. package/dist/universal/core-server.js +53 -22
  75. package/dist/universal/core.js +23 -6
  76. package/dist/universal/history.js +9 -0
  77. package/dist/universal/spec-driver.js +46 -50
  78. package/dist/{ufg/get-nml-client.js → utils/ensure-offline-folder.js} +14 -13
  79. package/dist/utils/extract-branching-timestamp.js +56 -0
  80. package/dist/utils/extract-current-commit.js +72 -0
  81. package/dist/utils/extract-git-info.js +168 -0
  82. package/dist/utils/extract-start-info.js +100 -0
  83. package/dist/utils/extract-test-environment.js +70 -0
  84. package/dist/utils/memory-usage-logging.js +46 -0
  85. package/dist/utils/populate-eyes-server-settings.js +41 -0
  86. package/dist/utils/validate-sdk-version.js +89 -0
  87. package/package.json +3 -3
  88. package/types/abort.d.ts +13 -0
  89. package/types/automation/abort.d.ts +16 -0
  90. package/types/automation/close.d.ts +14 -0
  91. package/types/automation/extract-text.d.ts +1 -1
  92. package/types/automation/get-nml-client.d.ts +16 -0
  93. package/types/automation/get-results.d.ts +11 -0
  94. package/types/automation/get-viewport-size.d.ts +1 -1
  95. package/types/automation/locate-text.d.ts +1 -1
  96. package/types/automation/locate.d.ts +1 -1
  97. package/types/automation/set-viewport-size.d.ts +1 -1
  98. package/types/automation/types.d.ts +107 -16
  99. package/types/automation/utils/report-kobiton.d.ts +12 -0
  100. package/types/automation/utils/take-screenshot.d.ts +5 -2
  101. package/types/automation/utils/to-base-check-settings.d.ts +13 -3
  102. package/types/automation/utils/to-environment-key.d.ts +2 -0
  103. package/types/automation/utils/uniquify-environments.d.ts +2 -0
  104. package/types/automation/utils/wait-for-lazy-load.d.ts +4 -8
  105. package/types/autonomous/core.d.ts +19 -0
  106. package/types/autonomous/create-render-results.d.ts +10 -0
  107. package/types/autonomous/create-render-target.d.ts +12 -0
  108. package/types/autonomous/get-render-results.d.ts +12 -0
  109. package/types/autonomous/open-eyes.d.ts +13 -0
  110. package/types/autonomous/start-renders.d.ts +12 -0
  111. package/types/autonomous/take-snapshots.d.ts +15 -0
  112. package/types/autonomous/types.d.ts +57 -0
  113. package/types/check-and-close.d.ts +3 -3
  114. package/types/check.d.ts +3 -3
  115. package/types/classic/check-and-close.d.ts +12 -5
  116. package/types/classic/check.d.ts +6 -3
  117. package/types/classic/core.d.ts +8 -2
  118. package/types/classic/get-base-eyes.d.ts +4 -8
  119. package/types/classic/open-eyes.d.ts +3 -4
  120. package/types/classic/types.d.ts +4 -5
  121. package/types/classic/utils/extract-default-environments.d.ts +9 -0
  122. package/types/classic/utils/take-dom-capture.d.ts +8 -0
  123. package/types/classic/utils/take-screenshots.d.ts +18 -0
  124. package/types/close-batch.d.ts +1 -1
  125. package/types/close.d.ts +3 -2
  126. package/types/core.d.ts +11 -2
  127. package/types/delete-test.d.ts +1 -1
  128. package/types/extract-text.d.ts +1 -1
  129. package/types/get-account-info.d.ts +11 -0
  130. package/types/get-ec-client.d.ts +1 -1
  131. package/types/get-eyes-results.d.ts +1 -1
  132. package/types/get-manager-results.d.ts +1 -1
  133. package/types/get-typed-eyes.d.ts +2 -4
  134. package/types/index.d.ts +2 -1
  135. package/types/lang.d.ts +32 -0
  136. package/types/locate-text.d.ts +1 -1
  137. package/types/locate.d.ts +1 -1
  138. package/types/make-manager.d.ts +11 -2
  139. package/types/offline/merge-configs.d.ts +1 -0
  140. package/types/offline/run-offline-snapshots.d.ts +11 -0
  141. package/types/open-eyes.d.ts +11 -2
  142. package/types/run-offline-snapshots.d.ts +6 -0
  143. package/types/troubleshoot/logs.d.ts +25 -0
  144. package/types/types.d.ts +19 -11
  145. package/types/ufg/check-and-close.d.ts +18 -10
  146. package/types/ufg/check.d.ts +5 -4
  147. package/types/ufg/core.d.ts +8 -5
  148. package/types/ufg/create-render-target-from-snapshot.d.ts +8 -0
  149. package/types/ufg/get-base-eyes.d.ts +4 -9
  150. package/types/ufg/get-ufg-client.d.ts +6 -3
  151. package/types/ufg/open-eyes.d.ts +3 -4
  152. package/types/ufg/take-snapshots.d.ts +17 -0
  153. package/types/ufg/types.d.ts +39 -39
  154. package/types/ufg/utils/extract-default-environment.d.ts +5 -0
  155. package/types/ufg/utils/generate-safe-selectors.d.ts +3 -12
  156. package/types/ufg/utils/take-dom-snapshot.d.ts +16 -21
  157. package/types/ufg/utils/take-dom-snapshots.d.ts +14 -10
  158. package/types/ufg/utils/to-generated-selectors.d.ts +34 -0
  159. package/types/ufg/utils/to-safe-check-settings.d.ts +22 -0
  160. package/types/universal/core-server.d.ts +6 -2
  161. package/types/universal/core.d.ts +6 -2
  162. package/types/universal/spec-driver.d.ts +6 -5
  163. package/types/universal/types.d.ts +59 -51
  164. package/types/utils/ensure-offline-folder.d.ts +1 -0
  165. package/types/utils/extract-branching-timestamp.d.ts +16 -0
  166. package/types/utils/extract-current-commit.d.ts +24 -0
  167. package/types/utils/extract-git-info.d.ts +59 -0
  168. package/types/utils/extract-start-info.d.ts +29 -0
  169. package/types/utils/extract-test-environment.d.ts +2 -0
  170. package/types/utils/memory-usage-logging.d.ts +7 -0
  171. package/types/utils/populate-eyes-server-settings.d.ts +2 -0
  172. package/types/utils/validate-sdk-version.d.ts +42 -0
  173. package/CHANGELOG.md +0 -222
  174. package/dist/classic/abort.js +0 -22
  175. package/dist/classic/close.js +0 -22
  176. package/dist/ufg/abort.js +0 -32
  177. package/dist/ufg/close.js +0 -37
  178. package/dist/ufg/get-results.js +0 -27
  179. package/dist/ufg/utils/take-vhses.js +0 -153
  180. package/dist/ufg/utils/uniquify-renderers.js +0 -27
  181. package/dist/utils/extract-ci-provider.js +0 -31
  182. package/types/classic/abort.d.ts +0 -16
  183. package/types/classic/close.d.ts +0 -16
  184. package/types/ufg/abort.d.ts +0 -21
  185. package/types/ufg/close.d.ts +0 -19
  186. package/types/ufg/get-nml-client.d.ts +0 -17
  187. package/types/ufg/get-results.d.ts +0 -16
  188. package/types/ufg/utils/take-vhses.d.ts +0 -17
  189. package/types/ufg/utils/uniquify-renderers.d.ts +0 -2
  190. package/types/utils/extract-ci-provider.d.ts +0 -1
@@ -0,0 +1,341 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.runOfflineSnapshots = void 0;
30
+ const fs_1 = __importDefault(require("fs"));
31
+ const path_1 = __importDefault(require("path"));
32
+ const core_1 = require("../core");
33
+ const get_ufg_client_1 = require("../ufg/get-ufg-client");
34
+ const logger_1 = require("@applitools/logger");
35
+ const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
36
+ const chalk_1 = __importDefault(require("chalk"));
37
+ const utils = __importStar(require("@applitools/utils"));
38
+ const merge_configs_1 = require("./merge-configs");
39
+ async function runOfflineSnapshots(options) {
40
+ var _a, _b;
41
+ if (!options.offlineLocationPath)
42
+ throw new Error('offlineLocationPath is required');
43
+ const offlineLocationPath = path_1.default.resolve(options.offlineLocationPath);
44
+ const startTime = Date.now();
45
+ const logger = (_a = options.logger) !== null && _a !== void 0 ? _a : (0, logger_1.makeLogger)({ format: { label: 'offline-exec' } });
46
+ const eyesServerSettings = { ...(_b = options.config) === null || _b === void 0 ? void 0 : _b.open, ...options };
47
+ const core = (0, core_1.makeCore)();
48
+ const account = await core.getAccountInfo({ settings: eyesServerSettings });
49
+ const ufgClient = await (0, get_ufg_client_1.makeGetUFGClient)({ logger })({
50
+ settings: { ...account.eyesServer, ...account.ufgServer },
51
+ });
52
+ const testFolders = (await fs_1.default.promises.readdir(offlineLocationPath))
53
+ .filter(filename => filename.startsWith('test-'))
54
+ .sort();
55
+ if (testFolders.length === 1) {
56
+ logger.console.log(`Running single test from folder ${offlineLocationPath}`);
57
+ }
58
+ else if (testFolders.length === 0) {
59
+ logger.console.log('No test artifacts were found at', offlineLocationPath);
60
+ }
61
+ else {
62
+ logger.console.log(`Running ${testFolders.length} tests from folder ${offlineLocationPath}`);
63
+ }
64
+ if (testFolders.length === 0) {
65
+ throw new Error(`Unable to find offline executions in ${offlineLocationPath}`);
66
+ }
67
+ const allTestResults = await runTests(testFolders);
68
+ const { isSuccess, outputStr } = processResults({ testResults: allTestResults, totalTime: Date.now() - startTime });
69
+ if (!isSuccess && options.failOnDiff) {
70
+ throw new Error(outputStr);
71
+ }
72
+ else {
73
+ logger.console.log(outputStr);
74
+ }
75
+ return allTestResults;
76
+ async function runTests(testFolders) {
77
+ logger.log('running tests', testFolders);
78
+ const results = await Promise.all(testFolders.map(async (testFolder) => {
79
+ const testLogger = logger.extend({ tags: [testFolder] });
80
+ const testPath = path_1.default.join(offlineLocationPath, testFolder);
81
+ const fileOpenSettings = await fs_1.default.promises
82
+ .readFile(path_1.default.join(testPath, 'settings.json'), 'utf-8')
83
+ .then(JSON.parse);
84
+ const openSettings = (0, merge_configs_1.mergeConfigs)(fileOpenSettings, options.config.open);
85
+ logger.console.log(`Running test: ${openSettings.testName} (${formatEnvironment(openSettings.environment)})`);
86
+ return runTest(testPath, openSettings, testLogger);
87
+ }));
88
+ const batchIds = [...new Set(results.map(t => t.batchId))];
89
+ const allTestResults = results.map(t => t.results);
90
+ logger.log('done running all tests', allTestResults);
91
+ await core.closeBatch({ settings: batchIds.map(batchId => ({ batchId, ...account.eyesServer })) });
92
+ logger.log('done closing batches');
93
+ return allTestResults;
94
+ }
95
+ async function runTest(testPath, openSettings, logger) {
96
+ const environment = await ufgClient.getActualEnvironment({
97
+ settings: { environment: openSettings.environment.requested },
98
+ });
99
+ const eyes = await core.base.openEyes({
100
+ settings: {
101
+ ...openSettings,
102
+ environment: {
103
+ ...openSettings.environment,
104
+ ...environment,
105
+ },
106
+ ...account.eyesServer,
107
+ },
108
+ logger,
109
+ });
110
+ const checkFolders = (await fs_1.default.promises.readdir(testPath)).filter(folderpath => folderpath.startsWith('check-'));
111
+ logger.log('running checks for test', testPath, ':', checkFolders);
112
+ const targets = (await Promise.all(checkFolders.map(checkFolder => fs_1.default.promises.readFile(path_1.default.resolve(testPath, checkFolder, 'snapshot.json'), 'utf-8').then(JSON.parse))));
113
+ await uploadResources(targets, logger);
114
+ // logger.log('resource hashes for test', testFolder, ':', resourceHashes)
115
+ logger.log('uploaded resources for test', testPath);
116
+ await Promise.all(targets.map((target, index) => runCheck(eyes, target, index, logger)));
117
+ const fileCloseSettings = await fs_1.default.promises.readFile(path_1.default.resolve(testPath, 'close.json'), 'utf-8').then(JSON.parse);
118
+ const closeSettings = (0, merge_configs_1.mergeConfigs)(fileCloseSettings, options.config.close);
119
+ await eyes.close({ settings: closeSettings });
120
+ logger.log('done running test', logger);
121
+ return { batchId: openSettings.batch.id, results: (await eyes.getResults({ logger }))[0] };
122
+ }
123
+ async function uploadResources(targets, logger) {
124
+ const uploadLogger = logger.extend({ tags: ['upload-resources'] });
125
+ const promises = targets.map(async ({ target }) => {
126
+ let resourcePromises = Object.values(target.resources)
127
+ .filter(isHashedResource)
128
+ .map(async (resource) => {
129
+ const contentfuleResource = {
130
+ id: '',
131
+ url: '',
132
+ value: await fs_1.default.promises.readFile(path_1.default.join(offlineLocationPath, 'resources', resource.hash)),
133
+ contentType: resource.contentType,
134
+ hash: resource,
135
+ };
136
+ return ufgClient.uploadResource({ resource: contentfuleResource, logger: uploadLogger });
137
+ });
138
+ resourcePromises = resourcePromises.concat(ufgClient.uploadResource({
139
+ resource: {
140
+ id: '',
141
+ url: '',
142
+ value: await fs_1.default.promises.readFile(path_1.default.join(offlineLocationPath, 'resources', target.snapshot.hash)),
143
+ contentType: target.snapshot.contentType,
144
+ hash: target.snapshot,
145
+ },
146
+ logger: uploadLogger,
147
+ }));
148
+ return Promise.all(resourcePromises);
149
+ });
150
+ await Promise.all(promises);
151
+ function isHashedResource(resource) {
152
+ return 'hash' in resource;
153
+ }
154
+ }
155
+ async function runCheck(eyes, target, index, logger) {
156
+ var _a;
157
+ const checkLogger = logger.extend({ tags: [`check-${index}`] });
158
+ const { elementReferences: selectors, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({
159
+ settings: target.settings,
160
+ });
161
+ const { renderId, selectorRegions, ...baseTarget } = await ufgClient.render({
162
+ target: target.target,
163
+ settings: {
164
+ ...target.settings,
165
+ region: (_a = selectors.target) !== null && _a !== void 0 ? _a : target.settings.region,
166
+ scrollRootElement: selectors.scrolling,
167
+ selectorsToCalculate: selectors.calculate,
168
+ includeFullPageSize: Boolean(target.settings.pageId),
169
+ environment: target.settings.environment,
170
+ uploadUrl: account.uploadUrl,
171
+ stitchingServiceUrl: account.stitchingServiceUrl,
172
+ },
173
+ logger: checkLogger,
174
+ });
175
+ const baseSettings = getBaseCheckSettings({
176
+ calculatedRegions: selectors.calculate.map((_, index) => {
177
+ var _a;
178
+ return ({
179
+ regions: (_a = selectorRegions === null || selectorRegions === void 0 ? void 0 : selectorRegions[index]) !== null && _a !== void 0 ? _a : [],
180
+ });
181
+ }),
182
+ });
183
+ baseSettings.renderId = renderId;
184
+ baseSettings.stepIndex = index;
185
+ baseTarget.source = target.target.source; // TODO verify
186
+ // baseTarget.name = snapshot.title // TODO figure out
187
+ const mergedCheckSettings = (0, merge_configs_1.mergeConfigs)(baseSettings, options.config.check);
188
+ await eyes.check({
189
+ target: { ...baseTarget, isTransformed: true },
190
+ settings: mergedCheckSettings,
191
+ logger: checkLogger,
192
+ });
193
+ }
194
+ }
195
+ exports.runOfflineSnapshots = runOfflineSnapshots;
196
+ function uniq(arr) {
197
+ return [...new Set(arr)];
198
+ }
199
+ function processResults({ testResults, totalTime, saveNewTests = true, failOnDiff = true, }) {
200
+ let outputStr = '\n';
201
+ const pluralize = utils.general.pluralize;
202
+ const testResultsWithErrors = testResults.filter(r => r && r.reason);
203
+ const unresolved = testResults.filter(r => r.isDifferent && !r.isAborted);
204
+ const passedOrNew = testResults.filter(r => r.status === 'Passed' || (r.isNew && !r.isAborted));
205
+ const aborted = testResults.filter(r => r.isAborted);
206
+ const newTests = testResults.filter(r => r.isNew && !r.isAborted);
207
+ const failedTests = testResults.filter(r => !r.reason && !r.isNew && !r.isAborted && !r.isDifferent && r.status === 'Failed');
208
+ const newTestsSize = newTests.length;
209
+ const warnForUnsavedNewTests = !!(!saveNewTests && newTestsSize);
210
+ const errMessagesToExclude = ['detected differences', 'Please approve the new baseline', 'is failed! See details at'];
211
+ const errors = testResultsWithErrors
212
+ .filter(r => !errMessagesToExclude.some(msg => { var _a, _b; return (_b = (_a = r.reason) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.includes(msg); }))
213
+ .map(r => ({
214
+ error: r.reason,
215
+ title: r.name,
216
+ }));
217
+ const hasResults = unresolved.length || passedOrNew.length || aborted.length;
218
+ const seeDetailsStr = hasResults && `See details at ${(passedOrNew[0] || unresolved[0] || aborted[0]).appUrls.batch}`;
219
+ if (hasResults) {
220
+ outputStr += `${seeDetailsStr}\n\n`;
221
+ }
222
+ outputStr += '[EYES: TEST RESULTS]:\n\n';
223
+ if (passedOrNew.length > 0) {
224
+ outputStr += testResultsOutput(passedOrNew, warnForUnsavedNewTests);
225
+ }
226
+ if (failedTests.length > 0) {
227
+ outputStr += testResultsOutput(failedTests, warnForUnsavedNewTests);
228
+ }
229
+ if (unresolved.length > 0) {
230
+ outputStr += testResultsOutput(unresolved, warnForUnsavedNewTests);
231
+ }
232
+ if (aborted.length > 0) {
233
+ outputStr += testResultsOutput(aborted, warnForUnsavedNewTests);
234
+ }
235
+ if (errors.length) {
236
+ const sortedErrors = errors.sort((a, b) => a.title.localeCompare(b.title));
237
+ outputStr += uniq(sortedErrors.map(({ title, error }) => `${title} - ${chalk_1.default.red('Failed')}. ${error.message || error.toString()}`)).join('\n');
238
+ outputStr += '\n';
239
+ }
240
+ if (!errors.length && !hasResults) {
241
+ outputStr += 'Test is finished but no results returned.\n';
242
+ }
243
+ const unresolvedOrFailed = unresolved.concat(failedTests);
244
+ if (errors.length && !unresolvedOrFailed.length) {
245
+ outputStr += chalk_1.default.red(`\nA total of ${errors.length} test${pluralize(errors.length)} failed for unexpected error${pluralize(errors.length)}.`);
246
+ }
247
+ else if (unresolvedOrFailed.length && !errors.length) {
248
+ outputStr += chalk_1.default.keyword(failedTests.length ? 'red' : 'orange')(`\nA total of ${unresolvedOrFailed.length} difference${pluralize(unresolvedOrFailed.length, [
249
+ 's were',
250
+ ' was',
251
+ ])} found.`);
252
+ }
253
+ else if (unresolvedOrFailed.length || errors.length) {
254
+ outputStr += chalk_1.default.red(`\nA total of ${unresolvedOrFailed.length} difference${pluralize(unresolvedOrFailed.length, [
255
+ 's were',
256
+ ' was',
257
+ ])} found and ${errors.length} test${pluralize(errors.length)} failed for ${pluralize(errors.length, [
258
+ '',
259
+ 'an ',
260
+ ])}unexpected error${pluralize(errors.length)}.`);
261
+ }
262
+ else if (warnForUnsavedNewTests) {
263
+ const countText = newTestsSize > 1 ? `are ${newTestsSize} new tests` : `is a new test: '${newTests[0].name}'`;
264
+ outputStr += chalk_1.default.red(`\n'saveNewTests' was set to false and there ${countText}. Please approve ${pluralize(newTestsSize, [
265
+ 'their',
266
+ 'its',
267
+ ])} baseline${pluralize(newTestsSize)} in Eyes dashboard.\n`);
268
+ }
269
+ else if (passedOrNew.length) {
270
+ outputStr += chalk_1.default.green(`\nNo differences were found!`);
271
+ }
272
+ if (hasResults) {
273
+ outputStr += `\n${seeDetailsStr}\nTotal time: ${Math.round(totalTime / 1000)} seconds\n`;
274
+ }
275
+ // if (Number(testConcurrency) === 5) {
276
+ // outputStr += `\n${concurrencyMsg}\n`
277
+ // }
278
+ let isSuccess;
279
+ if (errors.length) {
280
+ isSuccess = false;
281
+ }
282
+ else if (failOnDiff) {
283
+ isSuccess = !warnForUnsavedNewTests && passedOrNew.length && !unresolvedOrFailed.length;
284
+ }
285
+ else {
286
+ isSuccess = true;
287
+ }
288
+ return {
289
+ outputStr,
290
+ isSuccess,
291
+ };
292
+ }
293
+ function testResultsOutput(results, warnForUnsavedNewTests) {
294
+ let outputStr = '';
295
+ const sortedTestResults = results.sort((a, b) => a.name.localeCompare(b.name));
296
+ sortedTestResults.forEach(result => {
297
+ const testTitle = `${result.name} [${result.hostApp}] [${result.hostDisplaySize.width}x${result.hostDisplaySize.height}] - `;
298
+ if (result.isAborted) {
299
+ outputStr += `${testTitle}${chalk_1.default.keyword('red')(`Aborted`)}\n`;
300
+ }
301
+ else if (result.isNew) {
302
+ const newResColor = warnForUnsavedNewTests ? 'orange' : 'blue';
303
+ outputStr += `${testTitle}${chalk_1.default.keyword(newResColor)('New')}\n`;
304
+ }
305
+ else if (result.status === 'Passed') {
306
+ outputStr += `${testTitle}${chalk_1.default.green('Passed')}\n`;
307
+ }
308
+ else if (result.status === 'Failed') {
309
+ outputStr += `${testTitle}${chalk_1.default.keyword('red')('Failed')}\n`;
310
+ }
311
+ else {
312
+ outputStr += `${testTitle}${chalk_1.default.keyword('orange')(`Unresolved`)}\n`;
313
+ }
314
+ });
315
+ outputStr += '\n';
316
+ return outputStr;
317
+ }
318
+ function formatEnvironment(environment) {
319
+ const env = environment.requested;
320
+ if (isChromeEmulation(env)) {
321
+ return `${env.chromeEmulationInfo.deviceName}${env.chromeEmulationInfo.screenOrientation ? ` [${env.chromeEmulationInfo.screenOrientation}]` : ''}`;
322
+ }
323
+ else if (isIOSDevice(env)) {
324
+ return `${env.iosDeviceInfo.deviceName}${env.iosDeviceInfo.screenOrientation ? ` [${env.iosDeviceInfo.screenOrientation}]` : ''}`;
325
+ }
326
+ else if (isAndroidDevice(env)) {
327
+ return `${env.androidDeviceInfo.deviceName}${env.androidDeviceInfo.screenOrientation ? ` [${env.androidDeviceInfo.screenOrientation}]` : ''}`;
328
+ }
329
+ else {
330
+ return `${env.name} [${env.width}x${env.height}]`;
331
+ }
332
+ function isChromeEmulation(env) {
333
+ return env.chromeEmulationInfo;
334
+ }
335
+ function isIOSDevice(env) {
336
+ return env.iosDeviceInfo;
337
+ }
338
+ function isAndroidDevice(env) {
339
+ return env.androidDeviceInfo;
340
+ }
341
+ }
package/dist/open-eyes.js CHANGED
@@ -31,74 +31,218 @@ const get_typed_eyes_1 = require("./get-typed-eyes");
31
31
  const check_1 = require("./check");
32
32
  const check_and_close_1 = require("./check-and-close");
33
33
  const close_1 = require("./close");
34
+ const abort_1 = require("./abort");
34
35
  const get_eyes_results_1 = require("./get-eyes-results");
35
- const extract_ci_provider_1 = require("./utils/extract-ci-provider");
36
+ const populate_eyes_server_settings_1 = require("./utils/populate-eyes-server-settings");
36
37
  const utils = __importStar(require("@applitools/utils"));
37
- function makeOpenEyes({ type: defaultType = 'classic', concurrency, batch, core, cores, spec, logger: defaultLogger, }) {
38
- return async function openEyes({ type = defaultType, settings, config, target, logger = defaultLogger, }) {
39
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
40
- var _v, _w, _x, _y;
41
- settings = { ...config === null || config === void 0 ? void 0 : config.open, ...settings };
38
+ const core_base_1 = require("@applitools/core-base");
39
+ const extract_git_info_1 = require("./utils/extract-git-info");
40
+ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDuplicateTests, core, cores, spec, environment, logger: mainLogger, asyncCache, cwd = process.cwd(), }) {
41
+ return async function openEyes({ type = defaultType, settings: openSettings, config, target, logger = mainLogger, }) {
42
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
43
+ var _w, _x, _y, _z, _0;
44
+ logger = logger.extend(mainLogger, { tags: [`eyes-${type}-${utils.general.shortid()}`] });
45
+ const settings = { ...config === null || config === void 0 ? void 0 : config.open, ...openSettings };
46
+ const eyesServerSettings = (0, populate_eyes_server_settings_1.populateEyesServerSettings)(settings);
47
+ logger.mask(eyesServerSettings.apiKey);
48
+ logger.mask(eyesServerSettings.eyesServerUrl);
42
49
  (_a = settings.userTestId) !== null && _a !== void 0 ? _a : (settings.userTestId = `${settings.testName}--${utils.general.guid()}`);
43
- (_b = settings.serverUrl) !== null && _b !== void 0 ? _b : (settings.serverUrl = (_c = utils.general.getEnvValue('SERVER_URL')) !== null && _c !== void 0 ? _c : 'https://eyesapi.applitools.com');
44
- (_d = settings.apiKey) !== null && _d !== void 0 ? _d : (settings.apiKey = utils.general.getEnvValue('API_KEY'));
45
50
  settings.batch = { ...batch, ...settings.batch };
46
- (_e = (_v = settings.batch).id) !== null && _e !== void 0 ? _e : (_v.id = (_f = utils.general.getEnvValue('BATCH_ID')) !== null && _f !== void 0 ? _f : `generated-${utils.general.guid()}`);
47
- (_g = (_w = settings.batch).name) !== null && _g !== void 0 ? _g : (_w.name = utils.general.getEnvValue('BATCH_NAME'));
48
- (_h = (_x = settings.batch).sequenceName) !== null && _h !== void 0 ? _h : (_x.sequenceName = utils.general.getEnvValue('BATCH_SEQUENCE'));
49
- (_j = (_y = settings.batch).notifyOnCompletion) !== null && _j !== void 0 ? _j : (_y.notifyOnCompletion = utils.general.getEnvValue('BATCH_NOTIFY', 'boolean'));
50
- (_k = settings.keepBatchOpen) !== null && _k !== void 0 ? _k : (settings.keepBatchOpen = utils.general.getEnvValue('DONT_CLOSE_BATCHES', 'boolean'));
51
- (_l = settings.branchName) !== null && _l !== void 0 ? _l : (settings.branchName = utils.general.getEnvValue('BRANCH'));
52
- (_m = settings.parentBranchName) !== null && _m !== void 0 ? _m : (settings.parentBranchName = utils.general.getEnvValue('PARENT_BRANCH'));
53
- (_o = settings.baselineBranchName) !== null && _o !== void 0 ? _o : (settings.baselineBranchName = utils.general.getEnvValue('BASELINE_BRANCH'));
54
- (_p = settings.ignoreBaseline) !== null && _p !== void 0 ? _p : (settings.ignoreBaseline = false);
55
- (_q = settings.compareWithParentBranch) !== null && _q !== void 0 ? _q : (settings.compareWithParentBranch = false);
56
- const driver = target && (await (0, driver_1.makeDriver)({ spec, driver: target, logger, customConfig: settings }));
57
- const account = await core.getAccountInfo({
58
- settings: settings,
59
- logger,
60
- });
61
- if (account.ecEnabled) {
62
- const environment = await (driver === null || driver === void 0 ? void 0 : driver.getEnvironment());
63
- (_r = settings.properties) !== null && _r !== void 0 ? _r : (settings.properties = []);
64
- settings.properties.push({ name: 'Execution cloud', value: (environment === null || environment === void 0 ? void 0 : environment.isEC) ? 'Yes' : 'No' });
51
+ (_b = (_w = settings.batch).id) !== null && _b !== void 0 ? _b : (_w.id = (_c = utils.general.getEnvValue('BATCH_ID')) !== null && _c !== void 0 ? _c : `generated-${utils.general.guid()}`);
52
+ (_d = (_x = settings.batch).buildId) !== null && _d !== void 0 ? _d : (_x.buildId = utils.general.getEnvValue('BATCH_BUILD_ID'));
53
+ (_e = (_y = settings.batch).name) !== null && _e !== void 0 ? _e : (_y.name = utils.general.getEnvValue('BATCH_NAME'));
54
+ (_f = (_z = settings.batch).sequenceName) !== null && _f !== void 0 ? _f : (_z.sequenceName = utils.general.getEnvValue('BATCH_SEQUENCE'));
55
+ (_g = (_0 = settings.batch).notifyOnCompletion) !== null && _g !== void 0 ? _g : (_0.notifyOnCompletion = utils.general.getEnvValue('BATCH_NOTIFY', 'boolean'));
56
+ (_h = settings.keepBatchOpen) !== null && _h !== void 0 ? _h : (settings.keepBatchOpen = utils.general.getEnvValue('DONT_CLOSE_BATCHES', 'boolean'));
57
+ (_j = settings.branchName) !== null && _j !== void 0 ? _j : (settings.branchName = utils.general.getEnvValue('BRANCH'));
58
+ (_k = settings.parentBranchName) !== null && _k !== void 0 ? _k : (settings.parentBranchName = utils.general.getEnvValue('PARENT_BRANCH'));
59
+ (_l = settings.baselineBranchName) !== null && _l !== void 0 ? _l : (settings.baselineBranchName = utils.general.getEnvValue('BASELINE_BRANCH'));
60
+ (_m = settings.gitBranchingTimestamp) !== null && _m !== void 0 ? _m : (settings.gitBranchingTimestamp = utils.general.getEnvValue('GIT_MERGE_BASE_TIMESTAMP'));
61
+ (_o = settings.latestCommitInfo) !== null && _o !== void 0 ? _o : (settings.latestCommitInfo = getLatestCommitInfoFromEnvVars(logger));
62
+ (_p = settings.ufgServerUrl) !== null && _p !== void 0 ? _p : (settings.ufgServerUrl = utils.general.getEnvValue('UFG_SERVER_URL'));
63
+ (_q = settings.ignoreBaseline) !== null && _q !== void 0 ? _q : (settings.ignoreBaseline = false);
64
+ (_r = settings.compareWithParentBranch) !== null && _r !== void 0 ? _r : (settings.compareWithParentBranch = false);
65
+ (_s = settings.removeDuplicateTests) !== null && _s !== void 0 ? _s : (settings.removeDuplicateTests = removeDuplicateTests);
66
+ (_t = settings.latestCommitInfo) !== null && _t !== void 0 ? _t : (settings.latestCommitInfo = await (0, extract_git_info_1.extractLatestCommitInfo)({ execOptions: { cwd }, logger }));
67
+ if (settings.latestCommitInfo && !(0, extract_git_info_1.isISODate)(settings.latestCommitInfo.timestamp)) {
68
+ logger.warn(`latestCommitInfo.timestamp is an invalid ISO date string: ${settings.latestCommitInfo.timestamp}`);
69
+ settings.latestCommitInfo = undefined;
70
+ }
71
+ if (process.env.CI && (isRealBatchId(settings.batch.id) || settings.latestCommitInfo)) {
72
+ await populateAutoScmInfo(isRealBatchId(settings.batch.id) ? settings.batch.id : settings.latestCommitInfo.sha);
73
+ }
74
+ if (settings.ignoreGitBranching) {
75
+ settings.gitBranchingTimestamp = undefined;
76
+ }
77
+ else if (!settings.gitBranchingTimestamp) {
78
+ const { branchName, parentBranchName } = settings;
79
+ if (branchName && parentBranchName && branchName !== parentBranchName) {
80
+ settings.gitBranchingTimestamp = await (0, extract_git_info_1.extractBranchingTimestamp)({
81
+ branchName,
82
+ parentBranchName,
83
+ execOptions: { cwd },
84
+ logger,
85
+ });
86
+ }
65
87
  }
66
- core.logEvent({
88
+ if (settings.gitBranchingTimestamp && !(0, extract_git_info_1.isISODate)(settings.gitBranchingTimestamp)) {
89
+ logger.warn(`gitBranchingTimestamp is an invalid ISO date string: ${settings.gitBranchingTimestamp}`);
90
+ settings.gitBranchingTimestamp = undefined;
91
+ }
92
+ const driver = target && (await (0, driver_1.makeDriver)({ spec, driver: target, logger, customConfig: settings }));
93
+ const driverEnvironment = await (driver === null || driver === void 0 ? void 0 : driver.getEnvironment());
94
+ const driverUrl = await (driver === null || driver === void 0 ? void 0 : driver.getDriverUrl());
95
+ void core.logEvent({
67
96
  settings: {
68
- serverUrl: settings.serverUrl,
69
- apiKey: settings.apiKey,
70
- proxy: settings.proxy,
71
- agentId: settings.agentId,
97
+ ...settings,
72
98
  level: 'Notice',
73
99
  event: {
74
- type: 'runnerStarted',
75
- testConcurrency: concurrency,
76
- concurrentRendersPerTest: (_u = (_t = (_s = config === null || config === void 0 ? void 0 : config.check) === null || _s === void 0 ? void 0 : _s.renderers) === null || _t === void 0 ? void 0 : _t.length) !== null && _u !== void 0 ? _u : 1,
77
- node: { version: process.version, platform: process.platform, arch: process.arch },
78
- driverUrl: await (driver === null || driver === void 0 ? void 0 : driver.getDriverUrl()),
79
- extractedCIProvider: (0, extract_ci_provider_1.extractCIProvider)(),
100
+ type: 'openEyes',
101
+ userTestId: settings.userTestId,
102
+ concurrency: (_u = cores === null || cores === void 0 ? void 0 : cores[type].concurrency) !== null && _u !== void 0 ? _u : core.concurrency,
103
+ environment,
104
+ driver: {
105
+ deviceName: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.deviceName,
106
+ browserName: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.browserName,
107
+ browserVersion: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.browserVersion,
108
+ platformName: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.platformName,
109
+ platformVersion: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.platformVersion,
110
+ isApplitoolsLib: (_v = driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.applitoolsLib) === null || _v === void 0 ? void 0 : _v.instrumented,
111
+ isEC: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.isEC,
112
+ },
113
+ driverUrl,
80
114
  },
81
115
  },
82
116
  logger,
83
117
  });
118
+ if (settings.disableBrokerUrlCache && driver) {
119
+ await core.clearNMLClientCache(driver);
120
+ }
84
121
  const getTypedEyes = (0, get_typed_eyes_1.makeGetTypedEyes)({
85
122
  type,
86
123
  settings: settings,
87
124
  target: driver,
88
125
  cores: cores !== null && cores !== void 0 ? cores : {
89
- ufg: (0, core_2.makeCore)({ spec, base: core.base, concurrency: concurrency !== null && concurrency !== void 0 ? concurrency : 5, logger }),
90
- classic: (0, core_1.makeCore)({ spec, base: core.base, logger }),
126
+ ufg: (0, core_2.makeCore)({ spec, clients, base: core.base, asyncCache, logger }),
127
+ classic: (0, core_1.makeCore)({ spec, clients, base: core.base, logger }),
91
128
  },
92
129
  logger,
93
130
  });
94
- const eyes = await getTypedEyes({ logger });
95
- return utils.general.extend(eyes, eyes => ({
96
- getTypedEyes,
97
- check: (0, check_1.makeCheck)({ type, eyes, target: driver, spec, logger }),
98
- checkAndClose: (0, check_and_close_1.makeCheckAndClose)({ type, eyes, target: driver, spec, logger }),
99
- close: (0, close_1.makeClose)({ eyes, logger }),
100
- getResults: (0, get_eyes_results_1.makeGetEyesResults)({ eyes, logger }),
101
- })); // TODO solve the types issue
131
+ const eyes = await getTypedEyes({ logger }).catch(error => {
132
+ throw refineMissingApiKeyException(error, environment === null || environment === void 0 ? void 0 : environment.sdk);
133
+ });
134
+ return utils.general.extend(eyes, eyes => {
135
+ var _a, _b;
136
+ return ({
137
+ getTypedEyes,
138
+ check: (0, check_1.makeCheck)({ type, eyes, target: driver, spec, logger }),
139
+ checkAndClose: (0, check_and_close_1.makeCheckAndClose)({ type, eyes, target: driver, spec, logger }),
140
+ close: (0, close_1.makeClose)({ eyes, environments: (_a = config === null || config === void 0 ? void 0 : config.check) === null || _a === void 0 ? void 0 : _a.environments, logger }),
141
+ abort: (0, abort_1.makeAbort)({ eyes, environments: (_b = config === null || config === void 0 ? void 0 : config.check) === null || _b === void 0 ? void 0 : _b.environments, logger }),
142
+ getResults: (0, get_eyes_results_1.makeGetEyesResults)({ eyes, logger }),
143
+ });
144
+ }); // TODO solve the types issue
145
+ /////// END FUNCTION BODY ///////////////////
146
+ async function populateAutoScmInfo(batchId) {
147
+ var _a, _b;
148
+ var _c;
149
+ const branchName = await (0, extract_git_info_1.extractGitBranch)({ execOptions: { cwd }, logger });
150
+ const { owner: repoOwner, name: repoName } = await (0, extract_git_info_1.extractGitRepo)({ execOptions: { cwd }, logger });
151
+ const buildId = await (0, extract_git_info_1.extractBuildIdFromCI)();
152
+ if (branchName && repoOwner && repoName) {
153
+ const scmInfo = await core.base
154
+ .updateIfScm({
155
+ settings: { ...eyesServerSettings, batchId, branchName, repoOwner, repoName, buildId },
156
+ logger,
157
+ })
158
+ .catch(error => {
159
+ throw refineMissingApiKeyException(error, environment === null || environment === void 0 ? void 0 : environment.sdk);
160
+ });
161
+ if (scmInfo) {
162
+ (_a = settings.batch) !== null && _a !== void 0 ? _a : (settings.batch = {});
163
+ settings.batch.id = isRealBatchId(settings.batch.id) ? settings.batch.id : batchId;
164
+ (_b = (_c = settings.batch).buildId) !== null && _b !== void 0 ? _b : (_c.buildId = buildId);
165
+ // Intentionally not auto populating branchName and parentBranchName. If there is scmInfo then Eyes already knows these values.
166
+ }
167
+ }
168
+ else {
169
+ logger.log(`Skipping check for SCM integration due to missing information: branchName=${branchName} repoName=${repoName} repoOwner=${repoOwner}`);
170
+ }
171
+ }
102
172
  };
103
173
  }
104
174
  exports.makeOpenEyes = makeOpenEyes;
175
+ function refineMissingApiKeyException(error, sdk) {
176
+ var _a;
177
+ if (!sdk || typeof sdk !== 'object')
178
+ return error;
179
+ try {
180
+ if (error instanceof core_base_1.MissingApiKeyError) {
181
+ const apiKeyTutorials = {
182
+ python: {
183
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/python/#API',
184
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/python/#API',
185
+ 'eyes-robotframework': 'api-ref/sdk-api/robot/#API',
186
+ 'eyes-images': undefined,
187
+ },
188
+ ruby: {
189
+ eyes_images: 'api-ref/sdk-api/selenium/ruby/#API',
190
+ eyes_appium: undefined,
191
+ eyes_selenium: undefined,
192
+ eyes_universal: undefined,
193
+ eyes_capybara: undefined,
194
+ eyes_calabash: undefined,
195
+ },
196
+ java: {
197
+ java_appium: undefined,
198
+ java_selenium: 'api-ref/sdk-api/selenium/java/#API',
199
+ java_playwright: 'api-ref/sdk-api/playwright/java/#API',
200
+ java_images: undefined,
201
+ },
202
+ dotnet: {
203
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/csharp/#API',
204
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/csharp/#API',
205
+ 'eyes-appium': undefined,
206
+ 'eyes-appium2': undefined,
207
+ 'eyes-images': undefined,
208
+ },
209
+ js: {
210
+ 'eyes-images': undefined,
211
+ 'eyes-webdriverio': 'api-ref/sdk-api/wdio/#API',
212
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/javascript/#API',
213
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/javascript/#API',
214
+ 'eyes-puppeteer': 'api-ref/sdk-api/puppeteer/javascript/#API',
215
+ 'eyes-storybook': 'api-ref/sdk-api/storybook/#API',
216
+ 'eyes-cypress': 'api-ref/sdk-api/cypress/#API',
217
+ },
218
+ };
219
+ const { lang, name } = sdk !== null && sdk !== void 0 ? sdk : {};
220
+ const path = (_a = apiKeyTutorials[lang]) === null || _a === void 0 ? void 0 : _a[name];
221
+ if (path) {
222
+ error.message = error.message.replace('Default.html#cshid=api', path);
223
+ }
224
+ }
225
+ }
226
+ catch {
227
+ // if it fails, no harm done. The error message is fine without this refinement
228
+ return error;
229
+ }
230
+ return error;
231
+ }
232
+ function getLatestCommitInfoFromEnvVars(logger) {
233
+ const timestamp = utils.general.getEnvValue('GIT_LATEST_COMMIT_TIMESTAMP');
234
+ const sha = utils.general.getEnvValue('GIT_LATEST_COMMIT_SHA');
235
+ if (timestamp && sha) {
236
+ return { timestamp, sha };
237
+ }
238
+ else if (timestamp && !sha) {
239
+ logger.warn(`APPLITOOLS_GIT_LATEST_COMMIT_TIMESTAMP was provided without APPLITOOLS_GIT_LATEST_COMMIT_SHA. Proceeding provided timestamp ${timestamp} and NO_SHA_PROVIDED`);
240
+ return { timestamp, sha: 'NO_SHA_PROVIDED' };
241
+ }
242
+ else if (sha && !timestamp) {
243
+ logger.warn(`APPLITOOLS_GIT_LATEST_COMMIT_SHA was provided without APPLITOOLS_GIT_LATEST_COMMIT_TIMESTAMP. Not populating latestCommitInfo with the provided sha ${sha}.`);
244
+ }
245
+ }
246
+ function isRealBatchId(batchId) {
247
+ return !!batchId && !batchId.startsWith('generated');
248
+ }