@applitools/core 4.72.1 → 4.73.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.73.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.72.2...js/core@4.73.0) (2026-10-18)
4
+
5
+
6
+ ### Features
7
+
8
+ * read latestCommitInfo from git when cherry-pick lookup is on, log detection details | FLD-5129 ([#4293](https://github.com/Applitools-Dev/sdk/issues/4293)) ([0ec5dc8](https://github.com/Applitools-Dev/sdk/commit/0ec5dc86b4d78417cd2eb50cbaaf57d851556880))
9
+
10
+ ## [4.72.2](https://github.com/Applitools-Dev/sdk/compare/js/core@4.72.1...js/core@4.72.2) (2026-10-18)
11
+
12
+
13
+ ### Dependencies
14
+
15
+ * @applitools/nml-client bumped to 1.12.9
16
+
17
+ * @applitools/core-base bumped to 1.41.2
18
+ #### Bug Fixes
19
+
20
+ * read the heartbeat processId right before acquire | FLD-4169 ([#4320](https://github.com/Applitools-Dev/sdk/issues/4320)) ([a600eed](https://github.com/Applitools-Dev/sdk/commit/a600eeda613cb87f41d63a3583f7cd06d0602275))
21
+ * @applitools/ec-client bumped to 1.12.52
22
+
23
+
3
24
  ## [4.72.1](https://github.com/Applitools-Dev/sdk/compare/js/core@4.72.0...js/core@4.72.1) (2026-10-13)
4
25
 
5
26
 
package/dist/open-eyes.js CHANGED
@@ -40,6 +40,7 @@ const core_base_1 = require("@applitools/core-base");
40
40
  const extract_git_info_1 = require("./utils/extract-git-info");
41
41
  const types_1 = require("./types");
42
42
  const reportedScmPreconditionFindings = new Map();
43
+ const reportedCherryPickDetections = new Set();
43
44
  const scmPreconditionKey = (cwd, gitBranchName) => `${cwd} ${gitBranchName !== null && gitBranchName !== void 0 ? gitBranchName : ''}`;
44
45
  const findingsHash = (findings) => findings
45
46
  .map(finding => finding.code)
@@ -80,7 +81,10 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
80
81
  (_l = settings.parentBranchName) !== null && _l !== void 0 ? _l : (settings.parentBranchName = (_m = utils.general.getEnvValue('PARENT_BRANCH')) !== null && _m !== void 0 ? _m : utils.general.getEnvValue('PARENT_BRANCH_NAME'));
81
82
  (_o = settings.baselineBranchName) !== null && _o !== void 0 ? _o : (settings.baselineBranchName = (_p = utils.general.getEnvValue('BASELINE_BRANCH')) !== null && _p !== void 0 ? _p : utils.general.getEnvValue('BASELINE_BRANCH_NAME'));
82
83
  (_q = settings.gitBranchingTimestamp) !== null && _q !== void 0 ? _q : (settings.gitBranchingTimestamp = utils.general.getEnvValue('GIT_MERGE_BASE_TIMESTAMP'));
84
+ let latestCommitInfoSource = settings.latestCommitInfo ? 'settings' : undefined;
83
85
  (_r = settings.latestCommitInfo) !== null && _r !== void 0 ? _r : (settings.latestCommitInfo = getLatestCommitInfoFromEnvVars(logger));
86
+ if (settings.latestCommitInfo)
87
+ latestCommitInfoSource !== null && latestCommitInfoSource !== void 0 ? latestCommitInfoSource : (latestCommitInfoSource = 'env vars');
84
88
  (_s = settings.ufgServerUrl) !== null && _s !== void 0 ? _s : (settings.ufgServerUrl = utils.general.getEnvValue('UFG_SERVER_URL'));
85
89
  (_t = settings.ignoreBaseline) !== null && _t !== void 0 ? _t : (settings.ignoreBaseline = false);
86
90
  (_u = settings.compareWithParentBranch) !== null && _u !== void 0 ? _u : (settings.compareWithParentBranch = false);
@@ -90,6 +94,9 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
90
94
  logger.warn(`latestCommitInfo.timestamp is an invalid ISO date string: ${settings.latestCommitInfo.timestamp}`);
91
95
  settings.latestCommitInfo = undefined;
92
96
  }
97
+ if (settings.latestCommitInfo) {
98
+ logger.log(`Using latestCommitInfo from ${latestCommitInfoSource !== null && latestCommitInfoSource !== void 0 ? latestCommitInfoSource : 'git'}`, JSON.stringify(settings.latestCommitInfo));
99
+ }
93
100
  // Bare git refs from the scm integration. Kept out of `settings` because that pair is the
94
101
  // session's identity on the wire; these are only a `git merge-base` argument.
95
102
  let scmGitRefs;
@@ -134,7 +141,7 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
134
141
  }
135
142
  }
136
143
  const account = await core.getAccountInfo({ settings: eyesServerSettings, logger });
137
- await handleBranchFallbackList(account, settings, logger);
144
+ await handleBranchFallbackList(account, settings, latestCommitInfoSource, logger);
138
145
  const componentConcurrency = account.serverConcurrency.componentConcurrency;
139
146
  settings.sessionConcurrency = handleConcurrency({
140
147
  userConcurrency: concurrency,
@@ -225,8 +232,9 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
225
232
  }
226
233
  }
227
234
  };
228
- async function handleBranchFallbackList(account, settings, logger) {
229
- var _a, _b, _c;
235
+ async function handleBranchFallbackList(account, settings, latestCommitInfoSource, logger) {
236
+ var _a, _b, _c, _d;
237
+ logger.log('SCM settings from the server', JSON.stringify(account.scmSettings));
230
238
  const scm = getScmSettings(account.scmSettings);
231
239
  const integrationActive = !settings.ignoreGitBranching && scm.lookupFallbackList;
232
240
  // Extract gitBranchName (the actual git branch name)
@@ -242,7 +250,7 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
242
250
  // logger.log(`Using branch name: ${settings.branchName}`)
243
251
  }
244
252
  else {
245
- logger.log(`Skipping extraction of git branch name as ignoreGitBranching is set to true`);
253
+ logger.log(`Skipping extraction of git branch name: ignoreGitBranching=${settings.ignoreGitBranching}, fallback list enabled=${scm.lookupFallbackList}`);
246
254
  }
247
255
  // No branch name means the extractor never runs, so probe the env here instead.
248
256
  if (integrationActive && !settings.gitBranchName) {
@@ -266,7 +274,20 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
266
274
  settings.branchLookupFallbackList = outcome.list;
267
275
  // Walks from the same tip as latestCommitInfo (the PR head on pull_request events): the server compares the
268
276
  // pick positions with a cutoff taken from it.
277
+ let envLatestCommitSha;
269
278
  if (((_c = outcome.list) === null || _c === void 0 ? void 0 : _c.length) && settings.latestCommitInfo) {
279
+ // The env vars are often set once per CI pipeline and can point below the picks; git knows the real tip.
280
+ if (account.scmSettings.isCherryPickEnabled && latestCommitInfoSource === 'env vars') {
281
+ const gitCommitInfo = await (0, extract_git_info_1.extractLatestCommitInfo)({ execOptions: { cwd }, logger });
282
+ if (gitCommitInfo) {
283
+ logger.log(`Cherry-pick lookup is enabled for this account, so APPLITOOLS_GIT_LATEST_COMMIT_SHA/TIMESTAMP (${settings.latestCommitInfo.sha}) are ignored and latestCommitInfo is read from git`, JSON.stringify(gitCommitInfo));
284
+ envLatestCommitSha = settings.latestCommitInfo.sha;
285
+ settings.latestCommitInfo = gitCommitInfo;
286
+ }
287
+ else {
288
+ logger.log(`Cherry-pick lookup is enabled for this account, but git returned no commit, so latestCommitInfo stays on APPLITOOLS_GIT_LATEST_COMMIT_SHA (${settings.latestCommitInfo.sha})`);
289
+ }
290
+ }
270
291
  const cherryPicks = await (0, extract_git_info_1.extractCherryPicks)({
271
292
  headSha: settings.latestCommitInfo.sha,
272
293
  fallbackBranchNames: outcome.list.map(branch => branch.branchName),
@@ -275,6 +296,31 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
275
296
  });
276
297
  if (cherryPicks === null || cherryPicks === void 0 ? void 0 : cherryPicks.length)
277
298
  settings.cherryPicks = cherryPicks;
299
+ if (account.scmSettings.isCherryPickEnabled) {
300
+ reportCherryPickDetection({
301
+ account,
302
+ settings,
303
+ event: {
304
+ status: cherryPicks ? 'detected' : 'failed',
305
+ latestCommitInfoSource: envLatestCommitSha ? 'git' : latestCommitInfoSource !== null && latestCommitInfoSource !== void 0 ? latestCommitInfoSource : 'git',
306
+ latestCommitSha: settings.latestCommitInfo.sha,
307
+ envLatestCommitSha,
308
+ cherryPicks: cherryPicks === null || cherryPicks === void 0 ? void 0 : cherryPicks.map(({ pickedSha, originalSha, originalBranch }) => ({
309
+ pickedSha,
310
+ originalSha,
311
+ originalBranch,
312
+ })),
313
+ },
314
+ logger,
315
+ });
316
+ }
317
+ }
318
+ else {
319
+ const reason = ((_d = outcome.list) === null || _d === void 0 ? void 0 : _d.length) ? 'no latestCommitInfo' : 'empty fallback list';
320
+ logger.log(`Cherry-pick detection did not run: ${reason}`);
321
+ if (account.scmSettings.isCherryPickEnabled) {
322
+ reportCherryPickDetection({ account, settings, event: { status: 'skipped', reason }, logger });
323
+ }
278
324
  }
279
325
  if (outcome.status === 'precondition-failure') {
280
326
  reportScmPreconditionFailure({
@@ -295,6 +341,27 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
295
341
  reportedScmPreconditionFindings.set(key, hash);
296
342
  emitScmPreconditionFailureEvent({ account, settings, findings, defaultBranch, logger });
297
343
  }
344
+ function reportCherryPickDetection({ account, settings, event, logger, }) {
345
+ var _a, _b;
346
+ const key = `${cwd} ${settings.gitBranchName} ${(_a = settings.latestCommitInfo) === null || _a === void 0 ? void 0 : _a.sha}`;
347
+ if (reportedCherryPickDetections.has(key))
348
+ return;
349
+ reportedCherryPickDetections.add(key);
350
+ void core.logEvent({
351
+ settings: {
352
+ ...account.eyesServer,
353
+ level: event.envLatestCommitSha ? 'Warn' : 'Notice',
354
+ event: {
355
+ type: 'scmCherryPickDetection',
356
+ gitBranchName: settings.gitBranchName,
357
+ ...event,
358
+ batchId: (_b = settings.batch) === null || _b === void 0 ? void 0 : _b.id,
359
+ userTestId: settings.userTestId,
360
+ },
361
+ },
362
+ logger,
363
+ });
364
+ }
298
365
  function emitScmPreconditionFailureEvent({ account, settings, findings, defaultBranch, logger, }) {
299
366
  var _a;
300
367
  void core.logEvent({
@@ -1732,7 +1732,7 @@ function parsePickCandidate(record) {
1732
1732
  const [pickedSha, pickedCommitTime, body = ''] = record.replace(/^\n/, '').split('\x1f');
1733
1733
  // Hand-edited lines are not validated; the first line is trusted.
1734
1734
  const originalSha = (_a = body.match(CHERRY_PICK_LINE)) === null || _a === void 0 ? void 0 : _a[1];
1735
- return originalSha ? { pickedSha, pickedCommitTime, originalSha } : undefined;
1735
+ return originalSha ? { pickedSha, pickedCommitTime, originalSha, subject: body.split('\n')[0].trim() } : undefined;
1736
1736
  }
1737
1737
  async function collectPickCandidates(git, branches, headSha, logger) {
1738
1738
  const maxCommits = cherryPickLimit('CHERRY_PICK_MAX_COMMITS', 1000);
@@ -1745,6 +1745,7 @@ async function collectPickCandidates(git, branches, headSha, logger) {
1745
1745
  const records = log.stdout.split('\x1e').filter(record => record.trim());
1746
1746
  if (records.length === maxCommits)
1747
1747
  logger.log(`Cherry-pick detection read only the newest ${maxCommits} commits of ${range}`);
1748
+ logger.log(`Cherry-pick detection read ${records.length} commits of ${range}`);
1748
1749
  return records;
1749
1750
  });
1750
1751
  const candidates = new Map();
@@ -1779,18 +1780,19 @@ async function findContainingBranch(git, sha, branches) {
1779
1780
  async function resolvePick(git, candidate, branches, logger) {
1780
1781
  const originalSha = await resolveCommit(git, candidate.originalSha);
1781
1782
  if (!originalSha) {
1782
- logger.log(`Cherry-pick ${candidate.pickedSha} dropped: original ${candidate.originalSha} is not in the local history`);
1783
+ logger.log(`Cherry-pick ${candidate.pickedSha} "${candidate.subject}" dropped: original ${candidate.originalSha} is not in the local history`);
1783
1784
  return undefined;
1784
1785
  }
1785
1786
  const originalBranch = await findContainingBranch(git, originalSha, branches);
1786
1787
  if (!originalBranch) {
1787
- logger.log(`Cherry-pick ${candidate.pickedSha} dropped: original ${originalSha} is not on a fallback-list branch`);
1788
+ logger.log(`Cherry-pick ${candidate.pickedSha} "${candidate.subject}" dropped: original ${originalSha} is not on a fallback-list branch`);
1788
1789
  return undefined;
1789
1790
  }
1790
1791
  const shown = await git(['show', '-s', '--format=%aI', originalSha]);
1791
1792
  const originalCommitTime = shown.stdout.trim();
1792
1793
  if (shown.code !== 0 || !isISODate(originalCommitTime))
1793
1794
  throw new Error(`no commit time for ${originalSha}`);
1795
+ logger.log(`Cherry-pick ${candidate.pickedSha} "${candidate.subject}" is a pick of ${originalSha} on ${originalBranch}`);
1794
1796
  return {
1795
1797
  pickedSha: candidate.pickedSha,
1796
1798
  pickedCommitTime: candidate.pickedCommitTime,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/core",
3
- "version": "4.72.1",
3
+ "version": "4.73.0",
4
4
  "homepage": "https://applitools.com",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": {
@@ -55,14 +55,14 @@
55
55
  "test:ios-simulator": "MOCHA_ONLY_TAGS=ios-simulator MOCHA_GROUP=ios-simulator run --top-level mocha ./test/e2e/classic/webview.spec.ts --exit --require ./test/mocha-global-setup.js"
56
56
  },
57
57
  "dependencies": {
58
- "@applitools/core-base": "1.41.1",
58
+ "@applitools/core-base": "1.41.2",
59
59
  "@applitools/dom-capture": "11.8.8",
60
60
  "@applitools/dom-snapshot": "4.18.6",
61
61
  "@applitools/driver": "1.26.13",
62
- "@applitools/ec-client": "1.12.51",
62
+ "@applitools/ec-client": "1.12.52",
63
63
  "@applitools/image": "1.3.4",
64
64
  "@applitools/logger": "2.3.2",
65
- "@applitools/nml-client": "1.12.8",
65
+ "@applitools/nml-client": "1.12.9",
66
66
  "@applitools/req": "1.11.5",
67
67
  "@applitools/screenshoter": "3.12.35",
68
68
  "@applitools/snippets": "2.9.9",