@fern-api/replay 0.12.0 → 0.13.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/dist/cli.cjs CHANGED
@@ -13552,17 +13552,57 @@ var ReplayDetector = class {
13552
13552
  }
13553
13553
  const isAncestor = await this.git.isAncestor(lastGen.commit_sha, "HEAD");
13554
13554
  if (!isAncestor) {
13555
+ return this.detectPatchesViaMergeBase(lastGen, lock);
13556
+ }
13557
+ return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);
13558
+ }
13559
+ /**
13560
+ * FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.
13561
+ *
13562
+ * After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
13563
+ * `[fern-generated]`) is orphaned but still in git's object database. The
13564
+ * merge-base is the commit on main from which the bot's branch was created —
13565
+ * a reachable ancestor of HEAD. Walking that range and classifying each
13566
+ * commit via `isGenerationCommit` mirrors the linear path and eliminates
13567
+ * the bug class where pipeline-driven changes (autoversion, replay,
13568
+ * generation) get bundled as customer customizations.
13569
+ *
13570
+ * Falls through to the legacy composite path when no common ancestor exists
13571
+ * (truly disjoint history — orphan branches with no shared root).
13572
+ */
13573
+ async detectPatchesViaMergeBase(lastGen, lock) {
13574
+ let mergeBase = "";
13575
+ try {
13576
+ mergeBase = (await this.git.exec(["merge-base", lastGen.commit_sha, "HEAD"])).trim();
13577
+ } catch {
13578
+ }
13579
+ if (!mergeBase) {
13580
+ this.warnings.push(
13581
+ `No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. Falling back to composite tree-diff detection.`
13582
+ );
13555
13583
  return this.detectPatchesViaTreeDiff(
13556
13584
  lastGen,
13557
13585
  /* commitKnownMissing */
13558
13586
  false
13559
13587
  );
13560
13588
  }
13589
+ return this.detectPatchesInRange(mergeBase, lastGen, lock);
13590
+ }
13591
+ /**
13592
+ * FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one
13593
+ * `StoredPatch` per customer commit. Body shared by the linear path
13594
+ * (rangeStart = lastGen.commit_sha) and the merge-base path.
13595
+ *
13596
+ * Patch `base_generation` is always `lastGen.commit_sha` — the
13597
+ * lockfile-tracked reference the applicator uses to fetch base file
13598
+ * content, regardless of where the walk actually started.
13599
+ */
13600
+ async detectPatchesInRange(rangeStart, lastGen, lock) {
13561
13601
  const log = await this.git.exec([
13562
13602
  "log",
13563
13603
  "--first-parent",
13564
13604
  "--format=%H%x00%an%x00%ae%x00%s",
13565
- `${lastGen.commit_sha}..HEAD`,
13605
+ `${rangeStart}..HEAD`,
13566
13606
  "--",
13567
13607
  this.sdkOutputDir
13568
13608
  ]);