@fern-api/generator-cli 0.9.19 → 0.9.21
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.js +767 -123
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -7078,7 +7078,7 @@ var require_require_directory = __commonJS({
|
|
|
7078
7078
|
"../../node_modules/.pnpm/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module2) {
|
|
7079
7079
|
"use strict";
|
|
7080
7080
|
var fs3 = require("fs");
|
|
7081
|
-
var
|
|
7081
|
+
var join14 = require("path").join;
|
|
7082
7082
|
var resolve8 = require("path").resolve;
|
|
7083
7083
|
var dirname4 = require("path").dirname;
|
|
7084
7084
|
var defaultOptions2 = {
|
|
@@ -7115,7 +7115,7 @@ var require_require_directory = __commonJS({
|
|
|
7115
7115
|
}
|
|
7116
7116
|
path5 = !path5 ? dirname4(m.filename) : resolve8(dirname4(m.filename), path5);
|
|
7117
7117
|
fs3.readdirSync(path5).forEach(function(filename) {
|
|
7118
|
-
var joined =
|
|
7118
|
+
var joined = join14(path5, filename), files, key, obj;
|
|
7119
7119
|
if (fs3.statSync(joined).isDirectory() && options.recurse) {
|
|
7120
7120
|
files = requireDirectory(m, joined, options);
|
|
7121
7121
|
if (Object.keys(files).length) {
|
|
@@ -18885,7 +18885,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
18885
18885
|
if (!header)
|
|
18886
18886
|
return { value: "", type: null, comment: "", range: [start, start, start] };
|
|
18887
18887
|
const type = header.mode === ">" ? Scalar.Scalar.BLOCK_FOLDED : Scalar.Scalar.BLOCK_LITERAL;
|
|
18888
|
-
const lines = scalar.source ?
|
|
18888
|
+
const lines = scalar.source ? splitLines2(scalar.source) : [];
|
|
18889
18889
|
let chompStart = lines.length;
|
|
18890
18890
|
for (let i = lines.length - 1; i >= 0; --i) {
|
|
18891
18891
|
const content = lines[i][1];
|
|
@@ -19043,7 +19043,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
19043
19043
|
}
|
|
19044
19044
|
return { mode, indent, chomp, comment, length };
|
|
19045
19045
|
}
|
|
19046
|
-
function
|
|
19046
|
+
function splitLines2(source) {
|
|
19047
19047
|
const split = source.split(/\n( *)/);
|
|
19048
19048
|
const first2 = split[0];
|
|
19049
19049
|
const m = first2.match(/^( *)/);
|
|
@@ -22028,7 +22028,7 @@ var init_diff3 = __esm({
|
|
|
22028
22028
|
}
|
|
22029
22029
|
});
|
|
22030
22030
|
|
|
22031
|
-
// ../../node_modules/.pnpm/@fern-api+replay@0.
|
|
22031
|
+
// ../../node_modules/.pnpm/@fern-api+replay@0.14.0/node_modules/@fern-api/replay/dist/index.js
|
|
22032
22032
|
var dist_exports = {};
|
|
22033
22033
|
__export(dist_exports, {
|
|
22034
22034
|
CREDENTIAL_PATTERNS: () => CREDENTIAL_PATTERNS,
|
|
@@ -22401,11 +22401,43 @@ function threeWayMerge(base, ours, theirs) {
|
|
|
22401
22401
|
}
|
|
22402
22402
|
}
|
|
22403
22403
|
}
|
|
22404
|
-
|
|
22404
|
+
const result = {
|
|
22405
22405
|
content: outputLines.join("\n"),
|
|
22406
22406
|
hasConflicts: conflicts2.length > 0,
|
|
22407
22407
|
conflicts: conflicts2
|
|
22408
22408
|
};
|
|
22409
|
+
if (conflicts2.length === 0) {
|
|
22410
|
+
const dropped = computeDroppedContextLines(baseLines, theirsLines, outputLines);
|
|
22411
|
+
if (dropped.length > 0) {
|
|
22412
|
+
result.droppedContextLines = dropped;
|
|
22413
|
+
}
|
|
22414
|
+
}
|
|
22415
|
+
return result;
|
|
22416
|
+
}
|
|
22417
|
+
function computeDroppedContextLines(baseLines, theirsLines, mergedLines) {
|
|
22418
|
+
const baseCounts = countLines(baseLines);
|
|
22419
|
+
const theirsCounts = countLines(theirsLines);
|
|
22420
|
+
const mergedCounts = countLines(mergedLines);
|
|
22421
|
+
const dropped = [];
|
|
22422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22423
|
+
for (const line of baseLines) {
|
|
22424
|
+
if (seen.has(line)) continue;
|
|
22425
|
+
const inBase = baseCounts.get(line) ?? 0;
|
|
22426
|
+
const inTheirs = theirsCounts.get(line) ?? 0;
|
|
22427
|
+
const inMerged = mergedCounts.get(line) ?? 0;
|
|
22428
|
+
if (inBase > 0 && inTheirs > 0 && inMerged < Math.min(inBase, inTheirs)) {
|
|
22429
|
+
dropped.push(line);
|
|
22430
|
+
seen.add(line);
|
|
22431
|
+
}
|
|
22432
|
+
}
|
|
22433
|
+
return dropped;
|
|
22434
|
+
}
|
|
22435
|
+
function countLines(lines) {
|
|
22436
|
+
const counts = /* @__PURE__ */ new Map();
|
|
22437
|
+
for (const line of lines) {
|
|
22438
|
+
counts.set(line, (counts.get(line) ?? 0) + 1);
|
|
22439
|
+
}
|
|
22440
|
+
return counts;
|
|
22409
22441
|
}
|
|
22410
22442
|
function tryResolveConflict(oursLines, baseLines, theirsLines) {
|
|
22411
22443
|
if (baseLines.length === 0) {
|
|
@@ -22535,10 +22567,346 @@ function isBinaryFile(filePath) {
|
|
|
22535
22567
|
const ext2 = (0, import_path8.extname)(filePath).toLowerCase();
|
|
22536
22568
|
return BINARY_EXTENSIONS.has(ext2);
|
|
22537
22569
|
}
|
|
22570
|
+
function computeDroppedContextLinesForFile(base, theirs, finalContent) {
|
|
22571
|
+
const baseLines = base.split("\n");
|
|
22572
|
+
const theirsLines = theirs.split("\n");
|
|
22573
|
+
const finalLines = finalContent.split("\n");
|
|
22574
|
+
const baseCounts = /* @__PURE__ */ new Map();
|
|
22575
|
+
const theirsCounts = /* @__PURE__ */ new Map();
|
|
22576
|
+
const finalCounts = /* @__PURE__ */ new Map();
|
|
22577
|
+
for (const l of baseLines) baseCounts.set(l, (baseCounts.get(l) ?? 0) + 1);
|
|
22578
|
+
for (const l of theirsLines) theirsCounts.set(l, (theirsCounts.get(l) ?? 0) + 1);
|
|
22579
|
+
for (const l of finalLines) finalCounts.set(l, (finalCounts.get(l) ?? 0) + 1);
|
|
22580
|
+
const dropped = [];
|
|
22581
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22582
|
+
for (const line of baseLines) {
|
|
22583
|
+
if (seen.has(line)) continue;
|
|
22584
|
+
const inBase = baseCounts.get(line) ?? 0;
|
|
22585
|
+
const inTheirs = theirsCounts.get(line) ?? 0;
|
|
22586
|
+
const inFinal = finalCounts.get(line) ?? 0;
|
|
22587
|
+
if (inBase > 0 && inTheirs > 0 && inFinal < Math.min(inBase, inTheirs)) {
|
|
22588
|
+
dropped.push(line);
|
|
22589
|
+
seen.add(line);
|
|
22590
|
+
}
|
|
22591
|
+
}
|
|
22592
|
+
return dropped;
|
|
22593
|
+
}
|
|
22538
22594
|
function isDiffLineForFile(diffLine, filePath) {
|
|
22539
22595
|
const match2 = diffLine.match(/^diff --git a\/.+ b\/(.+)$/);
|
|
22540
22596
|
return match2 !== null && match2[1] === filePath;
|
|
22541
22597
|
}
|
|
22598
|
+
function normalizeHunkBody(hunk) {
|
|
22599
|
+
let contextC = 0;
|
|
22600
|
+
let removeC = 0;
|
|
22601
|
+
let addC = 0;
|
|
22602
|
+
const trimmed2 = [];
|
|
22603
|
+
for (const line of hunk.lines) {
|
|
22604
|
+
const oldUsed = contextC + removeC;
|
|
22605
|
+
const newUsed = contextC + addC;
|
|
22606
|
+
if (oldUsed >= hunk.oldCount && newUsed >= hunk.newCount) break;
|
|
22607
|
+
trimmed2.push(line);
|
|
22608
|
+
if (line.type === "context") contextC++;
|
|
22609
|
+
else if (line.type === "remove") removeC++;
|
|
22610
|
+
else if (line.type === "add") addC++;
|
|
22611
|
+
}
|
|
22612
|
+
return { ...hunk, lines: trimmed2 };
|
|
22613
|
+
}
|
|
22614
|
+
function extractFileDiffForFile(patchContent, filePath) {
|
|
22615
|
+
const lines = patchContent.split("\n");
|
|
22616
|
+
const out = [];
|
|
22617
|
+
let inTarget = false;
|
|
22618
|
+
for (const line of lines) {
|
|
22619
|
+
if (line.startsWith("diff --git")) {
|
|
22620
|
+
if (inTarget) break;
|
|
22621
|
+
if (isDiffLineForFile2(line, filePath)) {
|
|
22622
|
+
inTarget = true;
|
|
22623
|
+
out.push(line);
|
|
22624
|
+
}
|
|
22625
|
+
continue;
|
|
22626
|
+
}
|
|
22627
|
+
if (inTarget) out.push(line);
|
|
22628
|
+
}
|
|
22629
|
+
return out.length > 0 ? out.join("\n") + "\n" : null;
|
|
22630
|
+
}
|
|
22631
|
+
function isDiffLineForFile2(line, filePath) {
|
|
22632
|
+
const match2 = line.match(/^diff --git a\/(.+) b\/(.+)$/);
|
|
22633
|
+
return match2 !== null && (match2[2] === filePath || match2[1] === filePath);
|
|
22634
|
+
}
|
|
22635
|
+
async function computePerPatchDiff(patch, getCurrentGenContent, getWorkingTreeContent) {
|
|
22636
|
+
const fragments = [];
|
|
22637
|
+
const unlocatableFiles = [];
|
|
22638
|
+
for (const file of patch.files) {
|
|
22639
|
+
const fileDiff = extractFileDiffForFile(patch.patch_content, file);
|
|
22640
|
+
if (fileDiff == null) {
|
|
22641
|
+
unlocatableFiles.push(file);
|
|
22642
|
+
continue;
|
|
22643
|
+
}
|
|
22644
|
+
const hunksRaw = parseHunks(fileDiff).map(normalizeHunkBody);
|
|
22645
|
+
const hunks = hunksRaw.filter((h) => {
|
|
22646
|
+
if (h.lines.length === 0) return false;
|
|
22647
|
+
let ctx = 0, rm3 = 0, add = 0;
|
|
22648
|
+
for (const ln of h.lines) {
|
|
22649
|
+
if (ln.type === "context") ctx++;
|
|
22650
|
+
else if (ln.type === "remove") rm3++;
|
|
22651
|
+
else if (ln.type === "add") add++;
|
|
22652
|
+
}
|
|
22653
|
+
return ctx + rm3 === h.oldCount && ctx + add === h.newCount;
|
|
22654
|
+
});
|
|
22655
|
+
if (hunks.length === 0) {
|
|
22656
|
+
if (hunksRaw.length > 0) unlocatableFiles.push(file);
|
|
22657
|
+
continue;
|
|
22658
|
+
}
|
|
22659
|
+
const currentGen = await getCurrentGenContent(file);
|
|
22660
|
+
const workingTree = await getWorkingTreeContent(file);
|
|
22661
|
+
const isPureNewFile = hunks.every((h) => h.oldCount === 0);
|
|
22662
|
+
const isPureDelete = hunks.every((h) => h.newCount === 0);
|
|
22663
|
+
if (currentGen == null) {
|
|
22664
|
+
if (!isPureNewFile) {
|
|
22665
|
+
unlocatableFiles.push(file);
|
|
22666
|
+
continue;
|
|
22667
|
+
}
|
|
22668
|
+
if (workingTree == null) continue;
|
|
22669
|
+
fragments.push(synthesizeNewFileDiff(file, workingTree));
|
|
22670
|
+
continue;
|
|
22671
|
+
}
|
|
22672
|
+
if (isPureNewFile) {
|
|
22673
|
+
if (workingTree == null) {
|
|
22674
|
+
fragments.push(synthesizeDeleteFileDiff(file, currentGen));
|
|
22675
|
+
continue;
|
|
22676
|
+
}
|
|
22677
|
+
if (workingTree === currentGen) {
|
|
22678
|
+
continue;
|
|
22679
|
+
}
|
|
22680
|
+
const fullDiff = await unifiedDiff(currentGen, workingTree, file);
|
|
22681
|
+
if (fullDiff && fullDiff.trim()) fragments.push(fullDiff);
|
|
22682
|
+
continue;
|
|
22683
|
+
}
|
|
22684
|
+
if (workingTree == null) {
|
|
22685
|
+
if (!isPureDelete) {
|
|
22686
|
+
unlocatableFiles.push(file);
|
|
22687
|
+
continue;
|
|
22688
|
+
}
|
|
22689
|
+
fragments.push(synthesizeDeleteFileDiff(file, currentGen));
|
|
22690
|
+
continue;
|
|
22691
|
+
}
|
|
22692
|
+
const currentGenLines = splitLines(currentGen);
|
|
22693
|
+
const workingTreeLines = splitLines(workingTree);
|
|
22694
|
+
const locInCurrentGenRaw = locateHunksInOurs(hunks, currentGenLines);
|
|
22695
|
+
const locInWorkingTreeRaw = locateHunksInOurs(hunks, workingTreeLines);
|
|
22696
|
+
if (locInCurrentGenRaw == null || locInWorkingTreeRaw == null) {
|
|
22697
|
+
unlocatableFiles.push(file);
|
|
22698
|
+
continue;
|
|
22699
|
+
}
|
|
22700
|
+
const locInCurrentGen = locInCurrentGenRaw.map(
|
|
22701
|
+
(l) => resolveSpan(l, currentGenLines, "old")
|
|
22702
|
+
);
|
|
22703
|
+
const locInWorkingTree = locInWorkingTreeRaw.map(
|
|
22704
|
+
(l) => resolveSpan(l, workingTreeLines, "new")
|
|
22705
|
+
);
|
|
22706
|
+
const overlay = overlayRegions(
|
|
22707
|
+
currentGenLines,
|
|
22708
|
+
locInCurrentGen,
|
|
22709
|
+
workingTreeLines,
|
|
22710
|
+
locInWorkingTree
|
|
22711
|
+
);
|
|
22712
|
+
if (overlay === null) {
|
|
22713
|
+
unlocatableFiles.push(file);
|
|
22714
|
+
continue;
|
|
22715
|
+
}
|
|
22716
|
+
if (overlay === currentGen) {
|
|
22717
|
+
continue;
|
|
22718
|
+
}
|
|
22719
|
+
const fileUnifiedDiff = await unifiedDiff(currentGen, overlay, file);
|
|
22720
|
+
if (fileUnifiedDiff && fileUnifiedDiff.trim()) {
|
|
22721
|
+
fragments.push(fileUnifiedDiff);
|
|
22722
|
+
}
|
|
22723
|
+
}
|
|
22724
|
+
return {
|
|
22725
|
+
diff: fragments.join(""),
|
|
22726
|
+
unlocatableFiles
|
|
22727
|
+
};
|
|
22728
|
+
}
|
|
22729
|
+
async function computePerPatchDiffWithFallback(patch, getCurrentGenContent, getWorkingTreeContent, runCumulativeDiff) {
|
|
22730
|
+
const ppDiff = await computePerPatchDiff(
|
|
22731
|
+
patch,
|
|
22732
|
+
getCurrentGenContent,
|
|
22733
|
+
getWorkingTreeContent
|
|
22734
|
+
);
|
|
22735
|
+
if (ppDiff.unlocatableFiles.length === 0) {
|
|
22736
|
+
return { diff: ppDiff.diff, hadFallback: false, fallbackFiles: [] };
|
|
22737
|
+
}
|
|
22738
|
+
const cumulative = await runCumulativeDiff(ppDiff.unlocatableFiles);
|
|
22739
|
+
if (cumulative === null) {
|
|
22740
|
+
return null;
|
|
22741
|
+
}
|
|
22742
|
+
const merged = ppDiff.diff + (cumulative.trim() ? cumulative : "");
|
|
22743
|
+
return { diff: merged, hadFallback: true, fallbackFiles: ppDiff.unlocatableFiles };
|
|
22744
|
+
}
|
|
22745
|
+
function splitLines(content) {
|
|
22746
|
+
return content.split("\n");
|
|
22747
|
+
}
|
|
22748
|
+
function resolveSpan(loc, oursLines, prefer) {
|
|
22749
|
+
const { hunk, oursOffset } = loc;
|
|
22750
|
+
const oldSide = [];
|
|
22751
|
+
const newSide = [];
|
|
22752
|
+
for (const line of hunk.lines) {
|
|
22753
|
+
if (line.type === "context") {
|
|
22754
|
+
oldSide.push(line.content);
|
|
22755
|
+
newSide.push(line.content);
|
|
22756
|
+
} else if (line.type === "remove") {
|
|
22757
|
+
oldSide.push(line.content);
|
|
22758
|
+
} else if (line.type === "add") {
|
|
22759
|
+
newSide.push(line.content);
|
|
22760
|
+
}
|
|
22761
|
+
}
|
|
22762
|
+
const oldFits = sequenceMatches(oldSide, oursLines, oursOffset);
|
|
22763
|
+
const newFits = sequenceMatches(newSide, oursLines, oursOffset);
|
|
22764
|
+
if (prefer === "old") {
|
|
22765
|
+
if (oldFits) return { ...loc, oursSpan: hunk.oldCount };
|
|
22766
|
+
if (newFits) return { ...loc, oursSpan: hunk.newCount };
|
|
22767
|
+
} else {
|
|
22768
|
+
if (newFits) return { ...loc, oursSpan: hunk.newCount };
|
|
22769
|
+
if (oldFits) return { ...loc, oursSpan: hunk.oldCount };
|
|
22770
|
+
}
|
|
22771
|
+
return loc;
|
|
22772
|
+
}
|
|
22773
|
+
function sequenceMatches(needle, haystack, offset) {
|
|
22774
|
+
if (offset + needle.length > haystack.length) return false;
|
|
22775
|
+
for (let i = 0; i < needle.length; i++) {
|
|
22776
|
+
if (haystack[offset + i] !== needle[i]) return false;
|
|
22777
|
+
}
|
|
22778
|
+
return true;
|
|
22779
|
+
}
|
|
22780
|
+
function overlayRegions(currentGenLines, locInCurrentGen, workingTreeLines, locInWorkingTree) {
|
|
22781
|
+
if (locInCurrentGen.length !== locInWorkingTree.length) {
|
|
22782
|
+
return null;
|
|
22783
|
+
}
|
|
22784
|
+
const out = [];
|
|
22785
|
+
let cursor = 0;
|
|
22786
|
+
for (let i = 0; i < locInCurrentGen.length; i++) {
|
|
22787
|
+
const cg = locInCurrentGen[i];
|
|
22788
|
+
const wt = locInWorkingTree[i];
|
|
22789
|
+
if (cg.oursOffset > cursor) {
|
|
22790
|
+
out.push(...currentGenLines.slice(cursor, cg.oursOffset));
|
|
22791
|
+
}
|
|
22792
|
+
out.push(...workingTreeLines.slice(wt.oursOffset, wt.oursOffset + wt.oursSpan));
|
|
22793
|
+
cursor = cg.oursOffset + cg.oursSpan;
|
|
22794
|
+
}
|
|
22795
|
+
if (cursor < currentGenLines.length) {
|
|
22796
|
+
out.push(...currentGenLines.slice(cursor));
|
|
22797
|
+
}
|
|
22798
|
+
return out.join("\n");
|
|
22799
|
+
}
|
|
22800
|
+
async function unifiedDiff(beforeContent, afterContent, filePath) {
|
|
22801
|
+
if (beforeContent === afterContent) return "";
|
|
22802
|
+
const tmp3 = await (0, import_promises4.mkdtemp)((0, import_path10.join)((0, import_os2.tmpdir)(), "fern-replay-pp-"));
|
|
22803
|
+
try {
|
|
22804
|
+
const beforePath = (0, import_path10.join)(tmp3, "before");
|
|
22805
|
+
const afterPath = (0, import_path10.join)(tmp3, "after");
|
|
22806
|
+
await (0, import_promises4.writeFile)(beforePath, beforeContent, "utf-8");
|
|
22807
|
+
await (0, import_promises4.writeFile)(afterPath, afterContent, "utf-8");
|
|
22808
|
+
const raw = await runGitDiffNoIndex(beforePath, afterPath);
|
|
22809
|
+
if (!raw.trim()) return "";
|
|
22810
|
+
return rewriteDiffHeaders(raw, filePath);
|
|
22811
|
+
} finally {
|
|
22812
|
+
await (0, import_promises4.rm)(tmp3, { recursive: true, force: true });
|
|
22813
|
+
}
|
|
22814
|
+
}
|
|
22815
|
+
function runGitDiffNoIndex(beforePath, afterPath) {
|
|
22816
|
+
return new Promise((resolve22, reject) => {
|
|
22817
|
+
const proc = (0, import_child_process3.spawn)("git", ["diff", "--no-index", "--", beforePath, afterPath]);
|
|
22818
|
+
let stdout = "";
|
|
22819
|
+
let stderr = "";
|
|
22820
|
+
proc.stdout.on("data", (d) => stdout += d.toString());
|
|
22821
|
+
proc.stderr.on("data", (d) => stderr += d.toString());
|
|
22822
|
+
proc.on("close", (code) => {
|
|
22823
|
+
if (code === 0 || code === 1) resolve22(stdout);
|
|
22824
|
+
else reject(new Error(`git diff --no-index failed (code ${code}): ${stderr}`));
|
|
22825
|
+
});
|
|
22826
|
+
});
|
|
22827
|
+
}
|
|
22828
|
+
function rewriteDiffHeaders(raw, filePath) {
|
|
22829
|
+
const lines = raw.split("\n");
|
|
22830
|
+
const out = [];
|
|
22831
|
+
let seenFirstHeader = false;
|
|
22832
|
+
for (const line of lines) {
|
|
22833
|
+
if (line.startsWith("diff --git ")) {
|
|
22834
|
+
out.push(`diff --git a/${filePath} b/${filePath}`);
|
|
22835
|
+
seenFirstHeader = true;
|
|
22836
|
+
continue;
|
|
22837
|
+
}
|
|
22838
|
+
if (!seenFirstHeader) {
|
|
22839
|
+
continue;
|
|
22840
|
+
}
|
|
22841
|
+
if (line.startsWith("--- ")) {
|
|
22842
|
+
out.push(`--- a/${filePath}`);
|
|
22843
|
+
continue;
|
|
22844
|
+
}
|
|
22845
|
+
if (line.startsWith("+++ ")) {
|
|
22846
|
+
out.push(`+++ b/${filePath}`);
|
|
22847
|
+
continue;
|
|
22848
|
+
}
|
|
22849
|
+
out.push(line);
|
|
22850
|
+
}
|
|
22851
|
+
return out.join("\n");
|
|
22852
|
+
}
|
|
22853
|
+
function synthesizeNewFileDiff(file, content) {
|
|
22854
|
+
const lines = content.split("\n");
|
|
22855
|
+
const hasTrailingNewline = content.endsWith("\n");
|
|
22856
|
+
const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;
|
|
22857
|
+
const header = [
|
|
22858
|
+
`diff --git a/${file} b/${file}`,
|
|
22859
|
+
"new file mode 100644",
|
|
22860
|
+
"--- /dev/null",
|
|
22861
|
+
`+++ b/${file}`,
|
|
22862
|
+
`@@ -0,0 +1,${bodyLines.length} @@`
|
|
22863
|
+
].join("\n");
|
|
22864
|
+
const body = bodyLines.map((l) => `+${l}`).join("\n");
|
|
22865
|
+
const trailer = hasTrailingNewline ? "" : "\n\";
|
|
22866
|
+
return header + "\n" + body + trailer + "\n";
|
|
22867
|
+
}
|
|
22868
|
+
function synthesizeDeleteFileDiff(file, content) {
|
|
22869
|
+
const lines = content.split("\n");
|
|
22870
|
+
const hasTrailingNewline = content.endsWith("\n");
|
|
22871
|
+
const bodyLines = hasTrailingNewline ? lines.slice(0, -1) : lines;
|
|
22872
|
+
const header = [
|
|
22873
|
+
`diff --git a/${file} b/${file}`,
|
|
22874
|
+
"deleted file mode 100644",
|
|
22875
|
+
`--- a/${file}`,
|
|
22876
|
+
"+++ /dev/null",
|
|
22877
|
+
`@@ -1,${bodyLines.length} +0,0 @@`
|
|
22878
|
+
].join("\n");
|
|
22879
|
+
const body = bodyLines.map((l) => `-${l}`).join("\n");
|
|
22880
|
+
const trailer = hasTrailingNewline ? "" : "\n\";
|
|
22881
|
+
return header + "\n" + body + trailer + "\n";
|
|
22882
|
+
}
|
|
22883
|
+
function computeCommitBuckets(results, absorbedPatchIds, patchesPassedToCommit) {
|
|
22884
|
+
const resultByPatchId = /* @__PURE__ */ new Map();
|
|
22885
|
+
for (const r2 of results) resultByPatchId.set(r2.patch.id, r2);
|
|
22886
|
+
const applied = [];
|
|
22887
|
+
const unresolved = [];
|
|
22888
|
+
const absorbed = [];
|
|
22889
|
+
for (const patch of patchesPassedToCommit) {
|
|
22890
|
+
if (absorbedPatchIds.has(patch.id)) {
|
|
22891
|
+
absorbed.push(patch);
|
|
22892
|
+
continue;
|
|
22893
|
+
}
|
|
22894
|
+
const r2 = resultByPatchId.get(patch.id);
|
|
22895
|
+
if (!r2) {
|
|
22896
|
+
applied.push(patch);
|
|
22897
|
+
continue;
|
|
22898
|
+
}
|
|
22899
|
+
if (r2.status === "conflict" || patch.status === "unresolved") {
|
|
22900
|
+
unresolved.push(patch);
|
|
22901
|
+
continue;
|
|
22902
|
+
}
|
|
22903
|
+
if (r2.status === "applied") {
|
|
22904
|
+
applied.push(patch);
|
|
22905
|
+
continue;
|
|
22906
|
+
}
|
|
22907
|
+
}
|
|
22908
|
+
return { applied, unresolved, absorbed };
|
|
22909
|
+
}
|
|
22542
22910
|
async function bootstrap(outputDir, options) {
|
|
22543
22911
|
const git = new GitClient(outputDir);
|
|
22544
22912
|
const lockManager = new LockfileManager(outputDir);
|
|
@@ -22703,7 +23071,7 @@ function parseGitLog(log) {
|
|
|
22703
23071
|
});
|
|
22704
23072
|
}
|
|
22705
23073
|
function ensureFernignoreEntries(outputDir) {
|
|
22706
|
-
const fernignorePath = (0,
|
|
23074
|
+
const fernignorePath = (0, import_path12.join)(outputDir, ".fernignore");
|
|
22707
23075
|
let content = "";
|
|
22708
23076
|
if ((0, import_fs9.existsSync)(fernignorePath)) {
|
|
22709
23077
|
content = (0, import_fs9.readFileSync)(fernignorePath, "utf-8");
|
|
@@ -22726,7 +23094,7 @@ function ensureFernignoreEntries(outputDir) {
|
|
|
22726
23094
|
return true;
|
|
22727
23095
|
}
|
|
22728
23096
|
function ensureGitattributesEntries(outputDir) {
|
|
22729
|
-
const gitattributesPath = (0,
|
|
23097
|
+
const gitattributesPath = (0, import_path12.join)(outputDir, ".gitattributes");
|
|
22730
23098
|
let content = "";
|
|
22731
23099
|
if ((0, import_fs9.existsSync)(gitattributesPath)) {
|
|
22732
23100
|
content = (0, import_fs9.readFileSync)(gitattributesPath, "utf-8");
|
|
@@ -22921,7 +23289,7 @@ async function resolve7(outputDir, options) {
|
|
|
22921
23289
|
const resolvingPatches = lockManager.getResolvingPatches();
|
|
22922
23290
|
if (unresolvedPatches.length > 0) {
|
|
22923
23291
|
const applicator = new ReplayApplicator(git, lockManager, outputDir);
|
|
22924
|
-
await applicator.applyPatches(unresolvedPatches);
|
|
23292
|
+
await applicator.applyPatches(unresolvedPatches, { applyMode: "resolve" });
|
|
22925
23293
|
const markerFiles = await findConflictMarkerFiles(git);
|
|
22926
23294
|
if (markerFiles.length > 0) {
|
|
22927
23295
|
for (const patch of unresolvedPatches) {
|
|
@@ -22947,20 +23315,38 @@ async function resolve7(outputDir, options) {
|
|
|
22947
23315
|
if (patchesToCommit.length > 0) {
|
|
22948
23316
|
const currentGen = lock.current_generation;
|
|
22949
23317
|
const detector = new ReplayDetector(git, lockManager, outputDir);
|
|
23318
|
+
const warnings = [];
|
|
22950
23319
|
let patchesResolved = 0;
|
|
22951
23320
|
for (const patch of patchesToCommit) {
|
|
22952
|
-
const
|
|
22953
|
-
|
|
23321
|
+
const result = await computePerPatchDiffWithFallback(
|
|
23322
|
+
patch,
|
|
23323
|
+
(f2) => git.showFile(currentGen, f2),
|
|
23324
|
+
(f2) => (0, import_promises5.readFile)((0, import_path13.join)(outputDir, f2), "utf-8").catch(() => null),
|
|
23325
|
+
(files) => git.exec(["diff", currentGen, "--", ...files]).catch(() => null)
|
|
23326
|
+
);
|
|
23327
|
+
if (result === null) {
|
|
23328
|
+
warnings.push(
|
|
23329
|
+
`Patch ${patch.id}: cumulative-diff fallback failed for unlocatable files; preserving patch unchanged`
|
|
23330
|
+
);
|
|
23331
|
+
continue;
|
|
23332
|
+
}
|
|
23333
|
+
const diff = result.diff;
|
|
23334
|
+
if (!diff.trim()) {
|
|
22954
23335
|
lockManager.removePatch(patch.id);
|
|
22955
23336
|
continue;
|
|
22956
23337
|
}
|
|
23338
|
+
if (result.hadFallback) {
|
|
23339
|
+
warnings.push(
|
|
23340
|
+
`Patch ${patch.id}: ${result.fallbackFiles.join(", ")} could not be anchored; cumulative-diff fallback applied for those files`
|
|
23341
|
+
);
|
|
23342
|
+
}
|
|
22957
23343
|
const newContentHash = detector.computeContentHash(diff);
|
|
22958
|
-
const changedFiles = await getChangedFiles(git, currentGen, patch.files);
|
|
23344
|
+
const changedFiles = result.hadFallback ? await getChangedFiles(git, currentGen, patch.files) : extractFilesFromDiff(diff);
|
|
22959
23345
|
lockManager.markPatchResolved(patch.id, {
|
|
22960
23346
|
patch_content: diff,
|
|
22961
23347
|
content_hash: newContentHash,
|
|
22962
23348
|
base_generation: currentGen,
|
|
22963
|
-
files: changedFiles
|
|
23349
|
+
files: changedFiles.length > 0 ? changedFiles : patch.files
|
|
22964
23350
|
});
|
|
22965
23351
|
patchesResolved++;
|
|
22966
23352
|
}
|
|
@@ -22976,7 +23362,8 @@ async function resolve7(outputDir, options) {
|
|
|
22976
23362
|
success: true,
|
|
22977
23363
|
commitSha: commitSha2,
|
|
22978
23364
|
phase: "committed",
|
|
22979
|
-
patchesResolved
|
|
23365
|
+
patchesResolved,
|
|
23366
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
22980
23367
|
};
|
|
22981
23368
|
}
|
|
22982
23369
|
const committer = new ReplayCommitter(git, outputDir);
|
|
@@ -22994,6 +23381,24 @@ async function getChangedFiles(git, currentGen, files) {
|
|
|
22994
23381
|
const changed = filesOutput.trim().split("\n").filter(Boolean).filter((f2) => !f2.startsWith(".fern/"));
|
|
22995
23382
|
return changed.length > 0 ? changed : files;
|
|
22996
23383
|
}
|
|
23384
|
+
function extractFilesFromDiff(unifiedDiff2) {
|
|
23385
|
+
const out = /* @__PURE__ */ new Set();
|
|
23386
|
+
const renameSources = /* @__PURE__ */ new Set();
|
|
23387
|
+
let currentTarget = null;
|
|
23388
|
+
for (const line of unifiedDiff2.split("\n")) {
|
|
23389
|
+
const headerMatch = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
23390
|
+
if (headerMatch) {
|
|
23391
|
+
currentTarget = headerMatch[2];
|
|
23392
|
+
if (!currentTarget.startsWith(".fern/")) out.add(currentTarget);
|
|
23393
|
+
continue;
|
|
23394
|
+
}
|
|
23395
|
+
if (currentTarget && line.startsWith("rename from ")) {
|
|
23396
|
+
renameSources.add(line.slice("rename from ".length));
|
|
23397
|
+
}
|
|
23398
|
+
}
|
|
23399
|
+
for (const src of renameSources) out.delete(src);
|
|
23400
|
+
return Array.from(out);
|
|
23401
|
+
}
|
|
22997
23402
|
function status(outputDir) {
|
|
22998
23403
|
const lockManager = new LockfileManager(outputDir);
|
|
22999
23404
|
if (!lockManager.exists()) {
|
|
@@ -23041,9 +23446,9 @@ function status(outputDir) {
|
|
|
23041
23446
|
excludePatterns
|
|
23042
23447
|
};
|
|
23043
23448
|
}
|
|
23044
|
-
var import_fs6, import_path7, import_yaml, import_crypto, import_promises3, import_os, import_path8, import_fs7, import_path9, import_crypto2, import_fs8,
|
|
23449
|
+
var import_fs6, import_path7, import_yaml, import_crypto, import_promises3, import_os, import_path8, import_fs7, import_path9, import_promises4, import_os2, import_path10, import_child_process3, import_crypto2, import_fs8, import_path11, import_yaml2, import_crypto3, import_fs9, import_path12, import_fs10, import_promises5, import_path13, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, CREDENTIAL_PATTERNS, SENSITIVE_FILE_PATTERNS, FERN_BOT_NAME, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileNotFoundError, LockfileManager, INFRASTRUCTURE_FILES, ReplayDetector, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, BINARY_EXTENSIONS, ReplayApplicator, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
|
|
23045
23450
|
var init_dist3 = __esm({
|
|
23046
|
-
"../../node_modules/.pnpm/@fern-api+replay@0.
|
|
23451
|
+
"../../node_modules/.pnpm/@fern-api+replay@0.14.0/node_modules/@fern-api/replay/dist/index.js"() {
|
|
23047
23452
|
"use strict";
|
|
23048
23453
|
init_esm4();
|
|
23049
23454
|
import_fs6 = require("fs");
|
|
@@ -23058,16 +23463,22 @@ var init_dist3 = __esm({
|
|
|
23058
23463
|
import_fs7 = require("fs");
|
|
23059
23464
|
import_path9 = require("path");
|
|
23060
23465
|
init_esm3();
|
|
23466
|
+
import_promises4 = require("fs/promises");
|
|
23467
|
+
import_os2 = require("os");
|
|
23468
|
+
import_path10 = require("path");
|
|
23469
|
+
import_child_process3 = require("child_process");
|
|
23061
23470
|
import_crypto2 = require("crypto");
|
|
23062
23471
|
import_fs8 = require("fs");
|
|
23063
|
-
|
|
23472
|
+
import_path11 = require("path");
|
|
23064
23473
|
init_esm3();
|
|
23065
23474
|
import_yaml2 = __toESM(require_dist3(), 1);
|
|
23066
23475
|
import_crypto3 = require("crypto");
|
|
23067
23476
|
import_fs9 = require("fs");
|
|
23068
|
-
|
|
23477
|
+
import_path12 = require("path");
|
|
23069
23478
|
init_esm3();
|
|
23070
23479
|
import_fs10 = require("fs");
|
|
23480
|
+
import_promises5 = require("fs/promises");
|
|
23481
|
+
import_path13 = require("path");
|
|
23071
23482
|
__defProp3 = Object.defineProperty;
|
|
23072
23483
|
__getOwnPropNames3 = Object.getOwnPropertyNames;
|
|
23073
23484
|
__esm3 = (fn, res) => function __init() {
|
|
@@ -23095,9 +23506,9 @@ var init_dist3 = __esm({
|
|
|
23095
23506
|
return this.git.raw(args);
|
|
23096
23507
|
}
|
|
23097
23508
|
async execWithInput(args, input) {
|
|
23098
|
-
const { spawn:
|
|
23509
|
+
const { spawn: spawn22 } = await import("child_process");
|
|
23099
23510
|
return new Promise((resolve22, reject) => {
|
|
23100
|
-
const proc =
|
|
23511
|
+
const proc = spawn22("git", args, { cwd: this.repoPath });
|
|
23101
23512
|
let stdout = "";
|
|
23102
23513
|
let stderr = "";
|
|
23103
23514
|
proc.stdout.on("data", (data) => {
|
|
@@ -23457,17 +23868,57 @@ var init_dist3 = __esm({
|
|
|
23457
23868
|
}
|
|
23458
23869
|
const isAncestor = await this.git.isAncestor(lastGen.commit_sha, "HEAD");
|
|
23459
23870
|
if (!isAncestor) {
|
|
23871
|
+
return this.detectPatchesViaMergeBase(lastGen, lock);
|
|
23872
|
+
}
|
|
23873
|
+
return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);
|
|
23874
|
+
}
|
|
23875
|
+
/**
|
|
23876
|
+
* FER-10201 — Non-linear-history detection via `merge-base(prevGen, HEAD)`.
|
|
23877
|
+
*
|
|
23878
|
+
* After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
|
|
23879
|
+
* `[fern-generated]`) is orphaned but still in git's object database. The
|
|
23880
|
+
* merge-base is the commit on main from which the bot's branch was created —
|
|
23881
|
+
* a reachable ancestor of HEAD. Walking that range and classifying each
|
|
23882
|
+
* commit via `isGenerationCommit` mirrors the linear path and eliminates
|
|
23883
|
+
* the bug class where pipeline-driven changes (autoversion, replay,
|
|
23884
|
+
* generation) get bundled as customer customizations.
|
|
23885
|
+
*
|
|
23886
|
+
* Falls through to the legacy composite path when no common ancestor exists
|
|
23887
|
+
* (truly disjoint history — orphan branches with no shared root).
|
|
23888
|
+
*/
|
|
23889
|
+
async detectPatchesViaMergeBase(lastGen, lock) {
|
|
23890
|
+
let mergeBase = "";
|
|
23891
|
+
try {
|
|
23892
|
+
mergeBase = (await this.git.exec(["merge-base", lastGen.commit_sha, "HEAD"])).trim();
|
|
23893
|
+
} catch {
|
|
23894
|
+
}
|
|
23895
|
+
if (!mergeBase) {
|
|
23896
|
+
this.warnings.push(
|
|
23897
|
+
`No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. Falling back to composite tree-diff detection.`
|
|
23898
|
+
);
|
|
23460
23899
|
return this.detectPatchesViaTreeDiff(
|
|
23461
23900
|
lastGen,
|
|
23462
23901
|
/* commitKnownMissing */
|
|
23463
23902
|
false
|
|
23464
23903
|
);
|
|
23465
23904
|
}
|
|
23905
|
+
return this.detectPatchesInRange(mergeBase, lastGen, lock);
|
|
23906
|
+
}
|
|
23907
|
+
/**
|
|
23908
|
+
* FER-10201 — Walk `${rangeStart}..HEAD`, classify each commit, emit one
|
|
23909
|
+
* `StoredPatch` per customer commit. Body shared by the linear path
|
|
23910
|
+
* (rangeStart = lastGen.commit_sha) and the merge-base path.
|
|
23911
|
+
*
|
|
23912
|
+
* Patch `base_generation` is always `lastGen.commit_sha` — the
|
|
23913
|
+
* lockfile-tracked reference the applicator uses to fetch base file
|
|
23914
|
+
* content, regardless of where the walk actually started.
|
|
23915
|
+
*/
|
|
23916
|
+
async detectPatchesInRange(rangeStart, lastGen, lock) {
|
|
23466
23917
|
const log = await this.git.exec([
|
|
23467
23918
|
"log",
|
|
23468
23919
|
"--first-parent",
|
|
23469
23920
|
"--format=%H%x00%an%x00%ae%x00%s",
|
|
23470
|
-
`${
|
|
23921
|
+
`${rangeStart}..HEAD`,
|
|
23471
23922
|
"--",
|
|
23472
23923
|
this.sdkOutputDir
|
|
23473
23924
|
]);
|
|
@@ -23981,6 +24432,19 @@ var init_dist3 = __esm({
|
|
|
23981
24432
|
renameCache = /* @__PURE__ */ new Map();
|
|
23982
24433
|
treeExistsCache = /* @__PURE__ */ new Map();
|
|
23983
24434
|
fileTheirsAccumulator = /* @__PURE__ */ new Map();
|
|
24435
|
+
/**
|
|
24436
|
+
* Apply mode for the current `applyPatches` invocation. Set at the start
|
|
24437
|
+
* of `applyPatches`, read by `mergeFile` to decide:
|
|
24438
|
+
* - whether to skip the intra-loop marker strip (kept in `applyPatches`)
|
|
24439
|
+
* - whether to populate the accumulator after a conflicted merge
|
|
24440
|
+
* (resolve mode populates so subsequent patches on the same file
|
|
24441
|
+
* can use patch A's THEIRS as a structurally-correct merge base
|
|
24442
|
+
* when their diff was authored against post-A structure)
|
|
24443
|
+
* - whether to retry THEIRS reconstruction against the accumulator
|
|
24444
|
+
* when the BASE-relative reconstruction produced markers from a
|
|
24445
|
+
* cross-patch context mismatch
|
|
24446
|
+
*/
|
|
24447
|
+
currentApplyMode = "replay";
|
|
23984
24448
|
constructor(git, lockManager, outputDir) {
|
|
23985
24449
|
this.git = git;
|
|
23986
24450
|
this.lockManager = lockManager;
|
|
@@ -24028,8 +24492,23 @@ var init_dist3 = __esm({
|
|
|
24028
24492
|
/**
|
|
24029
24493
|
* Apply all patches, returning results for each.
|
|
24030
24494
|
* Skips patches that match exclude patterns in replay.yml
|
|
24495
|
+
*
|
|
24496
|
+
* `applyMode` controls the post-conflict marker strategy:
|
|
24497
|
+
* - `"replay"` (default): strip conflict markers from disk between
|
|
24498
|
+
* iterations whenever a later patch touches the same file. Lets the
|
|
24499
|
+
* follow-up patch's `git apply --3way` see clean OURS content,
|
|
24500
|
+
* which is what the silent-loss fix (PR #73) relies on. The replay
|
|
24501
|
+
* pipeline calls `revertConflictingFiles` after the loop to clean
|
|
24502
|
+
* any markers that survive.
|
|
24503
|
+
* - `"resolve"`: keep markers on disk. The resolve command needs the
|
|
24504
|
+
* customer to see them. Slow-path 3-way merge naturally preserves
|
|
24505
|
+
* A's markers and B's clean writes when their regions don't overlap;
|
|
24506
|
+
* when they do overlap, the customer gets nested markers and
|
|
24507
|
+
* resolves manually. Either way they aren't silently dropped.
|
|
24031
24508
|
*/
|
|
24032
|
-
async applyPatches(patches) {
|
|
24509
|
+
async applyPatches(patches, opts) {
|
|
24510
|
+
const applyMode = opts?.applyMode ?? "replay";
|
|
24511
|
+
this.currentApplyMode = applyMode;
|
|
24033
24512
|
this.resetAccumulator();
|
|
24034
24513
|
const results = [];
|
|
24035
24514
|
for (let i = 0; i < patches.length; i++) {
|
|
@@ -24044,7 +24523,7 @@ var init_dist3 = __esm({
|
|
|
24044
24523
|
}
|
|
24045
24524
|
const result = await this.applyPatchWithFallback(patch);
|
|
24046
24525
|
results.push(result);
|
|
24047
|
-
if (result.status === "conflict" && result.fileResults) {
|
|
24526
|
+
if (applyMode !== "resolve" && result.status === "conflict" && result.fileResults) {
|
|
24048
24527
|
const laterFiles = /* @__PURE__ */ new Set();
|
|
24049
24528
|
for (let j2 = i + 1; j2 < patches.length; j2++) {
|
|
24050
24529
|
for (const f2 of patches[j2].files) {
|
|
@@ -24074,9 +24553,17 @@ var init_dist3 = __esm({
|
|
|
24074
24553
|
}
|
|
24075
24554
|
return results;
|
|
24076
24555
|
}
|
|
24077
|
-
/**
|
|
24556
|
+
/**
|
|
24557
|
+
* Populate accumulator after git apply succeeds, AND collect per-file
|
|
24558
|
+
* results including any "dropped context lines" — lines that were
|
|
24559
|
+
* present in BASE and THEIRS (unchanged context) but absent from the
|
|
24560
|
+
* final on-disk state because OURS deleted them. This is the fast-path
|
|
24561
|
+
* counterpart to ThreeWayMerge.computeDroppedContextLines used by the
|
|
24562
|
+
* 3-way slow path; both must surface the same warning.
|
|
24563
|
+
*/
|
|
24078
24564
|
async populateAccumulatorForPatch(patch, baseGen, currentTreeHash) {
|
|
24079
|
-
|
|
24565
|
+
const fileResults = [];
|
|
24566
|
+
if (!baseGen) return fileResults;
|
|
24080
24567
|
const tempDir = await (0, import_promises3.mkdtemp)((0, import_path8.join)((0, import_os.tmpdir)(), "replay-acc-"));
|
|
24081
24568
|
const { GitClient: GitClient2 } = await Promise.resolve().then(() => (init_GitClient(), GitClient_exports));
|
|
24082
24569
|
const tempGit = new GitClient2(tempDir);
|
|
@@ -24089,18 +24576,30 @@ var init_dist3 = __esm({
|
|
|
24089
24576
|
const resolvedPath = await this.resolveFilePath(filePath, baseGen.tree_hash, currentTreeHash);
|
|
24090
24577
|
const base = await this.git.showFile(baseGen.tree_hash, filePath);
|
|
24091
24578
|
const theirs = await this.applyPatchToContent(base, patch.patch_content, filePath, tempGit, tempDir);
|
|
24092
|
-
const
|
|
24579
|
+
const finalOnDisk = await (0, import_promises3.readFile)((0, import_path8.join)(this.outputDir, resolvedPath), "utf-8").catch(() => null);
|
|
24580
|
+
const effectiveTheirs = theirs ?? finalOnDisk;
|
|
24093
24581
|
if (effectiveTheirs != null) {
|
|
24094
24582
|
this.fileTheirsAccumulator.set(resolvedPath, {
|
|
24095
24583
|
content: effectiveTheirs,
|
|
24096
24584
|
baseGeneration: patch.base_generation
|
|
24097
24585
|
});
|
|
24098
24586
|
}
|
|
24587
|
+
if (base != null && effectiveTheirs != null && finalOnDisk != null) {
|
|
24588
|
+
const dropped = computeDroppedContextLinesForFile(base, effectiveTheirs, finalOnDisk);
|
|
24589
|
+
if (dropped.length > 0) {
|
|
24590
|
+
fileResults.push({
|
|
24591
|
+
file: resolvedPath,
|
|
24592
|
+
status: "merged",
|
|
24593
|
+
droppedContextLines: dropped
|
|
24594
|
+
});
|
|
24595
|
+
}
|
|
24596
|
+
}
|
|
24099
24597
|
}
|
|
24100
24598
|
} finally {
|
|
24101
24599
|
await (0, import_promises3.rm)(tempDir, { recursive: true }).catch(() => {
|
|
24102
24600
|
});
|
|
24103
24601
|
}
|
|
24602
|
+
return fileResults;
|
|
24104
24603
|
}
|
|
24105
24604
|
async applyPatchWithFallback(patch) {
|
|
24106
24605
|
const baseGen = await this.resolveBaseGeneration(patch.base_generation);
|
|
@@ -24131,11 +24630,12 @@ var init_dist3 = __esm({
|
|
|
24131
24630
|
}
|
|
24132
24631
|
try {
|
|
24133
24632
|
await this.git.execWithInput(["apply", "--3way"], patch.patch_content);
|
|
24134
|
-
await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);
|
|
24633
|
+
const fastPathFileResults = await this.populateAccumulatorForPatch(patch, baseGen, currentTreeHash);
|
|
24135
24634
|
return {
|
|
24136
24635
|
patch,
|
|
24137
24636
|
status: "applied",
|
|
24138
24637
|
method: "git-am",
|
|
24638
|
+
...fastPathFileResults.length > 0 && { fileResults: fastPathFileResults },
|
|
24139
24639
|
...Object.keys(resolvedFiles).length > 0 && { resolvedFiles }
|
|
24140
24640
|
};
|
|
24141
24641
|
} catch {
|
|
@@ -24247,19 +24747,23 @@ var init_dist3 = __esm({
|
|
|
24247
24747
|
renameSourcePath
|
|
24248
24748
|
);
|
|
24249
24749
|
}
|
|
24750
|
+
const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);
|
|
24250
24751
|
if (theirs) {
|
|
24251
24752
|
const theirsHasMarkers = theirs.includes("<<<<<<< Generated") || theirs.includes(">>>>>>> Your customization");
|
|
24252
24753
|
const baseHasMarkers = base != null && (base.includes("<<<<<<< Generated") || base.includes(">>>>>>> Your customization"));
|
|
24253
24754
|
if (theirsHasMarkers && !baseHasMarkers) {
|
|
24254
|
-
|
|
24255
|
-
|
|
24256
|
-
|
|
24257
|
-
|
|
24258
|
-
|
|
24755
|
+
if (accumulatorEntry) {
|
|
24756
|
+
theirs = null;
|
|
24757
|
+
} else {
|
|
24758
|
+
return {
|
|
24759
|
+
file: resolvedPath,
|
|
24760
|
+
status: "skipped",
|
|
24761
|
+
reason: "stale-conflict-markers"
|
|
24762
|
+
};
|
|
24763
|
+
}
|
|
24259
24764
|
}
|
|
24260
24765
|
}
|
|
24261
24766
|
let useAccumulatorAsMergeBase = false;
|
|
24262
|
-
const accumulatorEntry = this.fileTheirsAccumulator.get(resolvedPath);
|
|
24263
24767
|
if (accumulatorEntry && (theirs == null || base == null)) {
|
|
24264
24768
|
theirs = await this.applyPatchToContent(
|
|
24265
24769
|
accumulatorEntry.content,
|
|
@@ -24366,7 +24870,8 @@ var init_dist3 = __esm({
|
|
|
24366
24870
|
const outDir = (0, import_path8.dirname)(oursPath);
|
|
24367
24871
|
await (0, import_promises3.mkdir)(outDir, { recursive: true });
|
|
24368
24872
|
await (0, import_promises3.writeFile)(oursPath, merged.content);
|
|
24369
|
-
|
|
24873
|
+
const populateAccumulator = effective_theirs != null && (!merged.hasConflicts || this.currentApplyMode === "resolve");
|
|
24874
|
+
if (populateAccumulator) {
|
|
24370
24875
|
this.fileTheirsAccumulator.set(resolvedPath, {
|
|
24371
24876
|
content: effective_theirs,
|
|
24372
24877
|
baseGeneration: patch.base_generation
|
|
@@ -24381,7 +24886,11 @@ var init_dist3 = __esm({
|
|
|
24381
24886
|
conflictMetadata: metadata
|
|
24382
24887
|
};
|
|
24383
24888
|
}
|
|
24384
|
-
return {
|
|
24889
|
+
return {
|
|
24890
|
+
file: resolvedPath,
|
|
24891
|
+
status: "merged",
|
|
24892
|
+
...merged.droppedContextLines && merged.droppedContextLines.length > 0 ? { droppedContextLines: merged.droppedContextLines } : {}
|
|
24893
|
+
};
|
|
24385
24894
|
} catch (error) {
|
|
24386
24895
|
return {
|
|
24387
24896
|
file: filePath,
|
|
@@ -24592,13 +25101,46 @@ CLI Version: ${options.cliVersion}`;
|
|
|
24592
25101
|
await this.git.exec(["commit", "-m", fullMessage]);
|
|
24593
25102
|
return (await this.git.exec(["rev-parse", "HEAD"])).trim();
|
|
24594
25103
|
}
|
|
24595
|
-
async commitReplay(_patchCount, patches, message) {
|
|
25104
|
+
async commitReplay(_patchCount, patches, message, options) {
|
|
24596
25105
|
await this.stageAll();
|
|
24597
25106
|
if (!await this.hasStagedChanges()) {
|
|
24598
25107
|
return (await this.git.exec(["rev-parse", "HEAD"])).trim();
|
|
24599
25108
|
}
|
|
24600
25109
|
let fullMessage = message ?? `[fern-replay] Applied customizations`;
|
|
24601
|
-
|
|
25110
|
+
const buckets = options?.buckets;
|
|
25111
|
+
if (buckets) {
|
|
25112
|
+
if (buckets.applied.length > 0) {
|
|
25113
|
+
fullMessage += `
|
|
25114
|
+
|
|
25115
|
+
Patches applied (${buckets.applied.length}):`;
|
|
25116
|
+
for (const p of buckets.applied) {
|
|
25117
|
+
fullMessage += `
|
|
25118
|
+
- ${p.id}: ${p.original_message}`;
|
|
25119
|
+
}
|
|
25120
|
+
}
|
|
25121
|
+
if (buckets.unresolved.length > 0) {
|
|
25122
|
+
fullMessage += `
|
|
25123
|
+
|
|
25124
|
+
Patches with unresolved conflicts (${buckets.unresolved.length}):`;
|
|
25125
|
+
for (const p of buckets.unresolved) {
|
|
25126
|
+
fullMessage += `
|
|
25127
|
+
- ${p.id}: ${p.original_message}`;
|
|
25128
|
+
}
|
|
25129
|
+
fullMessage += `
|
|
25130
|
+
Run \`fern-replay resolve\` to apply these customizations.`;
|
|
25131
|
+
}
|
|
25132
|
+
if (buckets.absorbed.length > 0) {
|
|
25133
|
+
fullMessage += `
|
|
25134
|
+
|
|
25135
|
+
Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
25136
|
+
for (const p of buckets.absorbed) {
|
|
25137
|
+
fullMessage += `
|
|
25138
|
+
- ${p.id}: ${p.original_message}`;
|
|
25139
|
+
}
|
|
25140
|
+
fullMessage += `
|
|
25141
|
+
The generator now produces these customizations natively.`;
|
|
25142
|
+
}
|
|
25143
|
+
} else if (patches && patches.length > 0) {
|
|
24602
25144
|
fullMessage += "\n\nPatches replayed:";
|
|
24603
25145
|
for (const patch of patches) {
|
|
24604
25146
|
fullMessage += `
|
|
@@ -24632,6 +25174,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
24632
25174
|
}
|
|
24633
25175
|
};
|
|
24634
25176
|
init_GitClient();
|
|
25177
|
+
init_HybridReconstruction();
|
|
24635
25178
|
ReplayService = class {
|
|
24636
25179
|
git;
|
|
24637
25180
|
detector;
|
|
@@ -25025,6 +25568,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25025
25568
|
if (newPatches.length > 0) {
|
|
25026
25569
|
results = await this.applicator.applyPatches(newPatches);
|
|
25027
25570
|
this._lastApplyResults = results;
|
|
25571
|
+
this.recordDroppedContextLineWarnings(results);
|
|
25028
25572
|
this.revertConflictingFiles(results);
|
|
25029
25573
|
for (const result of results) {
|
|
25030
25574
|
if (result.status === "conflict") {
|
|
@@ -25043,7 +25587,8 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25043
25587
|
if (newPatches.length > 0) {
|
|
25044
25588
|
if (!options?.stageOnly) {
|
|
25045
25589
|
const appliedCount = results.filter((r2) => r2.status === "applied").length;
|
|
25046
|
-
|
|
25590
|
+
const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, newPatches);
|
|
25591
|
+
await this.committer.commitReplay(appliedCount, newPatches, void 0, { buckets });
|
|
25047
25592
|
} else {
|
|
25048
25593
|
await this.committer.stageAll();
|
|
25049
25594
|
}
|
|
@@ -25106,12 +25651,21 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25106
25651
|
(p) => preRebasePatchIds.has(p.id) && !postRebasePatchIds.has(p.id)
|
|
25107
25652
|
);
|
|
25108
25653
|
existingPatches = this.lockManager.getPatches();
|
|
25109
|
-
const seenHashes = /* @__PURE__ */ new
|
|
25654
|
+
const seenHashes = /* @__PURE__ */ new Map();
|
|
25110
25655
|
for (const p of existingPatches) {
|
|
25111
|
-
|
|
25112
|
-
|
|
25656
|
+
const priorOrigin = seenHashes.get(p.content_hash);
|
|
25657
|
+
if (priorOrigin !== void 0) {
|
|
25658
|
+
const provenanceMissing = !priorOrigin || !p.original_commit;
|
|
25659
|
+
const sameOrigin = priorOrigin === p.original_commit;
|
|
25660
|
+
if (sameOrigin && !provenanceMissing) {
|
|
25661
|
+
this.lockManager.removePatch(p.id);
|
|
25662
|
+
} else {
|
|
25663
|
+
this.warnings.push(
|
|
25664
|
+
`Preserving patch ${p.id} (commit ${(p.original_commit || "<missing>").slice(0, 7)}): shares content_hash with a prior patch ${provenanceMissing ? "(provenance missing on at least one side)" : "from a different source commit"}. Both retained to avoid silent customization loss (FER-9983).`
|
|
25665
|
+
);
|
|
25666
|
+
}
|
|
25113
25667
|
} else {
|
|
25114
|
-
seenHashes.
|
|
25668
|
+
seenHashes.set(p.content_hash, p.original_commit);
|
|
25115
25669
|
}
|
|
25116
25670
|
}
|
|
25117
25671
|
existingPatches = this.lockManager.getPatches();
|
|
@@ -25172,6 +25726,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25172
25726
|
const genSha = prep._prepared.genSha;
|
|
25173
25727
|
const results = await this.applicator.applyPatches(allPatches);
|
|
25174
25728
|
this._lastApplyResults = results;
|
|
25729
|
+
this.recordDroppedContextLineWarnings(results);
|
|
25175
25730
|
this.revertConflictingFiles(results);
|
|
25176
25731
|
for (const result of results) {
|
|
25177
25732
|
if (result.status === "conflict") {
|
|
@@ -25199,7 +25754,8 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25199
25754
|
await this.committer.stageAll();
|
|
25200
25755
|
} else {
|
|
25201
25756
|
const appliedCount = results.filter((r2) => r2.status === "applied").length;
|
|
25202
|
-
|
|
25757
|
+
const buckets = computeCommitBuckets(results, rebaseCounts.absorbedPatchIds, allPatches);
|
|
25758
|
+
await this.committer.commitReplay(appliedCount, allPatches, void 0, { buckets });
|
|
25203
25759
|
}
|
|
25204
25760
|
const warnings = [...detectorWarnings, ...this.warnings];
|
|
25205
25761
|
return this.buildReport(
|
|
@@ -25223,7 +25779,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25223
25779
|
let repointed = 0;
|
|
25224
25780
|
let contentRebased = 0;
|
|
25225
25781
|
let keptAsUserOwned = 0;
|
|
25226
|
-
const seenContentHashes = /* @__PURE__ */ new
|
|
25782
|
+
const seenContentHashes = /* @__PURE__ */ new Map();
|
|
25227
25783
|
const absorbedPatchIds = /* @__PURE__ */ new Set();
|
|
25228
25784
|
const fernignorePatterns = this.readFernignorePatterns();
|
|
25229
25785
|
for (const result of results) {
|
|
@@ -25237,6 +25793,23 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25237
25793
|
}
|
|
25238
25794
|
}
|
|
25239
25795
|
}
|
|
25796
|
+
const conflictedFilePaths = /* @__PURE__ */ new Set();
|
|
25797
|
+
for (const r2 of results) {
|
|
25798
|
+
if (r2.status !== "conflict") continue;
|
|
25799
|
+
if (r2.fileResults) {
|
|
25800
|
+
for (const fr of r2.fileResults) {
|
|
25801
|
+
if (fr.status !== "conflict") continue;
|
|
25802
|
+
conflictedFilePaths.add(fr.file);
|
|
25803
|
+
if (r2.resolvedFiles) {
|
|
25804
|
+
for (const [orig, resolved] of Object.entries(r2.resolvedFiles)) {
|
|
25805
|
+
if (resolved === fr.file) conflictedFilePaths.add(orig);
|
|
25806
|
+
}
|
|
25807
|
+
}
|
|
25808
|
+
}
|
|
25809
|
+
} else {
|
|
25810
|
+
for (const f2 of r2.patch.files) conflictedFilePaths.add(f2);
|
|
25811
|
+
}
|
|
25812
|
+
}
|
|
25240
25813
|
for (const result of results) {
|
|
25241
25814
|
if (result.status === "conflict" && result.fileResults) {
|
|
25242
25815
|
await this.trimAbsorbedFiles(result, currentGenSha);
|
|
@@ -25304,6 +25877,18 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25304
25877
|
keptAsUserOwned++;
|
|
25305
25878
|
continue;
|
|
25306
25879
|
}
|
|
25880
|
+
const overlapsConflicted = patch.files.some((f2) => conflictedFilePaths.has(f2));
|
|
25881
|
+
if (overlapsConflicted) {
|
|
25882
|
+
patch.status = "unresolved";
|
|
25883
|
+
try {
|
|
25884
|
+
this.lockManager.updatePatch(patch.id, { status: "unresolved" });
|
|
25885
|
+
} catch {
|
|
25886
|
+
}
|
|
25887
|
+
this.warnings.push(
|
|
25888
|
+
`Patch ${patch.id} (${patch.original_message}) was preserved as unresolved because an earlier patch conflicted on the same file(s) (${patch.files.join(", ")}). Run \`fern replay resolve\` to apply this customization manually.`
|
|
25889
|
+
);
|
|
25890
|
+
continue;
|
|
25891
|
+
}
|
|
25307
25892
|
this.lockManager.removePatch(patch.id);
|
|
25308
25893
|
absorbedPatchIds.add(patch.id);
|
|
25309
25894
|
absorbed++;
|
|
@@ -25319,13 +25904,22 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25319
25904
|
continue;
|
|
25320
25905
|
}
|
|
25321
25906
|
const newContentHash = this.detector.computeContentHash(diff);
|
|
25322
|
-
|
|
25323
|
-
|
|
25324
|
-
|
|
25325
|
-
|
|
25326
|
-
|
|
25907
|
+
const priorOrigin = seenContentHashes.get(newContentHash);
|
|
25908
|
+
if (priorOrigin !== void 0) {
|
|
25909
|
+
const provenanceMissing = !priorOrigin || !patch.original_commit;
|
|
25910
|
+
const sameOrigin = priorOrigin === patch.original_commit;
|
|
25911
|
+
if (sameOrigin && !provenanceMissing) {
|
|
25912
|
+
this.lockManager.removePatch(patch.id);
|
|
25913
|
+
absorbedPatchIds.add(patch.id);
|
|
25914
|
+
absorbed++;
|
|
25915
|
+
continue;
|
|
25916
|
+
}
|
|
25917
|
+
this.warnings.push(
|
|
25918
|
+
`Preserving patch ${patch.id} (commit ${(patch.original_commit || "<missing>").slice(0, 7)}): shares content_hash with a prior patch ${provenanceMissing ? "(provenance missing on at least one side)" : "from a different source commit"}. Both retained to avoid silent customization loss (FER-9983).`
|
|
25919
|
+
);
|
|
25920
|
+
} else {
|
|
25921
|
+
seenContentHashes.set(newContentHash, patch.original_commit);
|
|
25327
25922
|
}
|
|
25328
|
-
seenContentHashes.add(newContentHash);
|
|
25329
25923
|
patch.base_generation = currentGenSha;
|
|
25330
25924
|
patch.patch_content = diff;
|
|
25331
25925
|
patch.content_hash = newContentHash;
|
|
@@ -25501,8 +26095,14 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25501
26095
|
}
|
|
25502
26096
|
if (patch.base_generation === currentGen) {
|
|
25503
26097
|
try {
|
|
25504
|
-
const
|
|
25505
|
-
|
|
26098
|
+
const ppResult = await computePerPatchDiffWithFallback(
|
|
26099
|
+
patch,
|
|
26100
|
+
(f2) => this.git.showFile(currentGen, f2),
|
|
26101
|
+
(f2) => this.git.showFile("HEAD", f2),
|
|
26102
|
+
(files) => this.git.exec(["diff", currentGen, "HEAD", "--", ...files]).catch(() => null)
|
|
26103
|
+
);
|
|
26104
|
+
if (ppResult === null) continue;
|
|
26105
|
+
const diff = ppResult.diff;
|
|
25506
26106
|
if (!diff.trim()) {
|
|
25507
26107
|
if (await allPatchFilesUserOwned(patch)) continue;
|
|
25508
26108
|
this.lockManager.removePatch(patch.id);
|
|
@@ -25544,8 +26144,14 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25544
26144
|
try {
|
|
25545
26145
|
const markerFiles = await this.git.exec(["grep", "-l", "<<<<<<< Generated", "HEAD", "--", ...patch.files]).catch(() => "");
|
|
25546
26146
|
if (markerFiles.trim()) continue;
|
|
25547
|
-
const
|
|
25548
|
-
|
|
26147
|
+
const ppResult = await computePerPatchDiffWithFallback(
|
|
26148
|
+
patch,
|
|
26149
|
+
(f2) => this.git.showFile(currentGen, f2),
|
|
26150
|
+
(f2) => this.git.showFile("HEAD", f2),
|
|
26151
|
+
(files) => this.git.exec(["diff", currentGen, "HEAD", "--", ...files]).catch(() => null)
|
|
26152
|
+
);
|
|
26153
|
+
if (ppResult === null) continue;
|
|
26154
|
+
const diff = ppResult.diff;
|
|
25549
26155
|
if (!diff.trim()) {
|
|
25550
26156
|
if (await allPatchFilesUserOwned(patch)) {
|
|
25551
26157
|
try {
|
|
@@ -25570,6 +26176,32 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25570
26176
|
}
|
|
25571
26177
|
return { conflictResolved, conflictAbsorbed, contentRefreshed };
|
|
25572
26178
|
}
|
|
26179
|
+
/**
|
|
26180
|
+
* After applyPatches(), surface a warning for each (patch × file) where
|
|
26181
|
+
* diff3 silently dropped lines that were unchanged context in the
|
|
26182
|
+
* customer's THEIRS. The deletion stays on disk (correct diff3 outcome),
|
|
26183
|
+
* but the customer must learn so they can re-add the lines if they
|
|
26184
|
+
* relied on them. This is the "surface or preserve, never silently drop"
|
|
26185
|
+
* contract for legitimate-deletion cases.
|
|
26186
|
+
*/
|
|
26187
|
+
recordDroppedContextLineWarnings(results) {
|
|
26188
|
+
const PREVIEW_COUNT = 5;
|
|
26189
|
+
for (const result of results) {
|
|
26190
|
+
if (!result.fileResults) continue;
|
|
26191
|
+
for (const fr of result.fileResults) {
|
|
26192
|
+
const dropped = fr.droppedContextLines;
|
|
26193
|
+
if (!dropped || dropped.length === 0) continue;
|
|
26194
|
+
const preview = dropped.slice(0, PREVIEW_COUNT).map((line) => ` ${line}`).join("\n");
|
|
26195
|
+
const more = dropped.length > PREVIEW_COUNT ? `
|
|
26196
|
+
... and ${dropped.length - PREVIEW_COUNT} more` : "";
|
|
26197
|
+
this.warnings.push(
|
|
26198
|
+
`${fr.file}: ${dropped.length} line(s) that appeared as unchanged context in your customization were deleted by the new generator output. The merge followed the deletion. First lines deleted:
|
|
26199
|
+
${preview}${more}
|
|
26200
|
+
If you want to keep these lines, restore them in a follow-up commit and re-run replay; otherwise this warning can be safely ignored.`
|
|
26201
|
+
);
|
|
26202
|
+
}
|
|
26203
|
+
}
|
|
26204
|
+
}
|
|
25573
26205
|
/**
|
|
25574
26206
|
* After applyPatches(), strip conflict markers from conflicting files
|
|
25575
26207
|
* so only clean content is committed. Keeps the Generated (OURS) side.
|
|
@@ -25627,6 +26259,9 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25627
26259
|
};
|
|
25628
26260
|
}).filter((d) => d.files.length > 0);
|
|
25629
26261
|
const partialCount = conflictDetails.filter((d) => d.cleanFiles && d.cleanFiles.length > 0).length;
|
|
26262
|
+
const unresolvedResults = results.filter(
|
|
26263
|
+
(r2) => r2.status === "conflict" || r2.patch.status === "unresolved"
|
|
26264
|
+
);
|
|
25630
26265
|
return {
|
|
25631
26266
|
flow,
|
|
25632
26267
|
patchesDetected: patches.length,
|
|
@@ -25643,7 +26278,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25643
26278
|
patchesRefreshed: preRebaseCounts && preRebaseCounts.contentRefreshed > 0 ? preRebaseCounts.contentRefreshed : void 0,
|
|
25644
26279
|
conflicts: conflictResults.flatMap((r2) => r2.fileResults?.filter((f2) => f2.status === "conflict") ?? []),
|
|
25645
26280
|
conflictDetails: conflictDetails.length > 0 ? conflictDetails : void 0,
|
|
25646
|
-
unresolvedPatches:
|
|
26281
|
+
unresolvedPatches: unresolvedResults.length > 0 ? unresolvedResults.map((r2) => ({
|
|
25647
26282
|
patchId: r2.patch.id,
|
|
25648
26283
|
patchMessage: r2.patch.original_message,
|
|
25649
26284
|
files: r2.patch.files,
|
|
@@ -25664,10 +26299,10 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25664
26299
|
this.outputDir = outputDir;
|
|
25665
26300
|
}
|
|
25666
26301
|
fernignoreExists() {
|
|
25667
|
-
return (0, import_fs8.existsSync)((0,
|
|
26302
|
+
return (0, import_fs8.existsSync)((0, import_path11.join)(this.outputDir, ".fernignore"));
|
|
25668
26303
|
}
|
|
25669
26304
|
readFernignorePatterns() {
|
|
25670
|
-
const fernignorePath = (0,
|
|
26305
|
+
const fernignorePath = (0, import_path11.join)(this.outputDir, ".fernignore");
|
|
25671
26306
|
if (!(0, import_fs8.existsSync)(fernignorePath)) {
|
|
25672
26307
|
return [];
|
|
25673
26308
|
}
|
|
@@ -25727,7 +26362,16 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25727
26362
|
original_author: "Fern Replay <replay@buildwithfern.com>",
|
|
25728
26363
|
base_generation: currentGen.commit_sha,
|
|
25729
26364
|
files: patchFiles,
|
|
25730
|
-
patch_content: patchContent
|
|
26365
|
+
patch_content: patchContent,
|
|
26366
|
+
// Synthetic patches captured from .fernignore-protected files
|
|
26367
|
+
// are user-owned by definition — the customer's content
|
|
26368
|
+
// diverges from the generator's pristine output, and the
|
|
26369
|
+
// generator never produced this divergent content. Without
|
|
26370
|
+
// this flag, removing the file from .fernignore later (so
|
|
26371
|
+
// it leaves the protection check in `isFileUserOwned`) would
|
|
26372
|
+
// expose the patch to absorption on the next regen,
|
|
26373
|
+
// silently losing the customization.
|
|
26374
|
+
user_owned: true
|
|
25731
26375
|
});
|
|
25732
26376
|
trackedByBoth.push({
|
|
25733
26377
|
file: pattern,
|
|
@@ -25760,7 +26404,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25760
26404
|
return results;
|
|
25761
26405
|
}
|
|
25762
26406
|
readFileContent(filePath) {
|
|
25763
|
-
const fullPath = (0,
|
|
26407
|
+
const fullPath = (0, import_path11.join)(this.outputDir, filePath);
|
|
25764
26408
|
if (!(0, import_fs8.existsSync)(fullPath)) {
|
|
25765
26409
|
return null;
|
|
25766
26410
|
}
|
|
@@ -25825,7 +26469,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25825
26469
|
};
|
|
25826
26470
|
}
|
|
25827
26471
|
movePatternsToReplayYml(patterns) {
|
|
25828
|
-
const replayYmlPath = (0,
|
|
26472
|
+
const replayYmlPath = (0, import_path11.join)(this.outputDir, ".fern", "replay.yml");
|
|
25829
26473
|
let config = {};
|
|
25830
26474
|
if ((0, import_fs8.existsSync)(replayYmlPath)) {
|
|
25831
26475
|
const content = (0, import_fs8.readFileSync)(replayYmlPath, "utf-8");
|
|
@@ -25834,7 +26478,7 @@ CLI Version: ${options.cliVersion}`;
|
|
|
25834
26478
|
const existing = config.exclude ?? [];
|
|
25835
26479
|
const merged = [.../* @__PURE__ */ new Set([...existing, ...patterns])];
|
|
25836
26480
|
config.exclude = merged;
|
|
25837
|
-
const dir = (0,
|
|
26481
|
+
const dir = (0, import_path11.dirname)(replayYmlPath);
|
|
25838
26482
|
if (!(0, import_fs8.existsSync)(dir)) {
|
|
25839
26483
|
(0, import_fs8.mkdirSync)(dir, { recursive: true });
|
|
25840
26484
|
}
|
|
@@ -26338,7 +26982,7 @@ var require_cross_spawn = __commonJS({
|
|
|
26338
26982
|
var cp2 = require("child_process");
|
|
26339
26983
|
var parse3 = require_parse2();
|
|
26340
26984
|
var enoent = require_enoent();
|
|
26341
|
-
function
|
|
26985
|
+
function spawn3(command, args, options) {
|
|
26342
26986
|
const parsed = parse3(command, args, options);
|
|
26343
26987
|
const spawned = cp2.spawn(parsed.command, parsed.args, parsed.options);
|
|
26344
26988
|
enoent.hookChildProcess(spawned, parsed);
|
|
@@ -26350,8 +26994,8 @@ var require_cross_spawn = __commonJS({
|
|
|
26350
26994
|
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
|
26351
26995
|
return result;
|
|
26352
26996
|
}
|
|
26353
|
-
module2.exports =
|
|
26354
|
-
module2.exports.spawn =
|
|
26997
|
+
module2.exports = spawn3;
|
|
26998
|
+
module2.exports.spawn = spawn3;
|
|
26355
26999
|
module2.exports.sync = spawnSync;
|
|
26356
27000
|
module2.exports._parse = parse3;
|
|
26357
27001
|
module2.exports._enoent = enoent;
|
|
@@ -28390,8 +29034,8 @@ function resolve(...paths) {
|
|
|
28390
29034
|
|
|
28391
29035
|
// src/cli.ts
|
|
28392
29036
|
var import_fs15 = __toESM(require("fs"));
|
|
28393
|
-
var
|
|
28394
|
-
var
|
|
29037
|
+
var import_promises13 = require("fs/promises");
|
|
29038
|
+
var import_path20 = __toESM(require("path"));
|
|
28395
29039
|
|
|
28396
29040
|
// ../../node_modules/.pnpm/yargs@17.7.2/node_modules/yargs/build/lib/yerror.js
|
|
28397
29041
|
var YError = class _YError extends Error {
|
|
@@ -38092,42 +38736,42 @@ function replayForget(params) {
|
|
|
38092
38736
|
// src/replay/replay-init.ts
|
|
38093
38737
|
init_dist3();
|
|
38094
38738
|
var import_fs11 = require("fs");
|
|
38095
|
-
var
|
|
38739
|
+
var import_path15 = require("path");
|
|
38096
38740
|
var import_tmp_promise2 = __toESM(require_tmp_promise());
|
|
38097
38741
|
|
|
38098
38742
|
// src/replay/fernignore.ts
|
|
38099
|
-
var
|
|
38100
|
-
var
|
|
38743
|
+
var import_promises6 = require("fs/promises");
|
|
38744
|
+
var import_path14 = require("path");
|
|
38101
38745
|
var REPLAY_FERNIGNORE_ENTRIES2 = [".fern/replay.lock", ".fern/replay.yml", ".gitattributes"];
|
|
38102
38746
|
var GITATTRIBUTES_ENTRIES2 = [".fern/replay.lock linguist-generated=true"];
|
|
38103
38747
|
async function ensureReplayFernignoreEntries(outputDir) {
|
|
38104
|
-
const fernignorePath = (0,
|
|
38748
|
+
const fernignorePath = (0, import_path14.join)(outputDir, ".fernignore");
|
|
38105
38749
|
let content = "";
|
|
38106
38750
|
try {
|
|
38107
|
-
content = await (0,
|
|
38751
|
+
content = await (0, import_promises6.readFile)(fernignorePath, "utf-8");
|
|
38108
38752
|
} catch {
|
|
38109
38753
|
}
|
|
38110
38754
|
const lines = content.split("\n");
|
|
38111
38755
|
const toAdd = REPLAY_FERNIGNORE_ENTRIES2.filter((entry) => !lines.some((line) => line.trim() === entry));
|
|
38112
38756
|
if (toAdd.length > 0) {
|
|
38113
38757
|
const suffix = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
38114
|
-
await (0,
|
|
38758
|
+
await (0, import_promises6.writeFile)(fernignorePath, content + suffix + toAdd.join("\n") + "\n", "utf-8");
|
|
38115
38759
|
return true;
|
|
38116
38760
|
}
|
|
38117
38761
|
return false;
|
|
38118
38762
|
}
|
|
38119
38763
|
async function ensureGitattributesEntries2(outputDir) {
|
|
38120
|
-
const gitattributesPath = (0,
|
|
38764
|
+
const gitattributesPath = (0, import_path14.join)(outputDir, ".gitattributes");
|
|
38121
38765
|
let content = "";
|
|
38122
38766
|
try {
|
|
38123
|
-
content = await (0,
|
|
38767
|
+
content = await (0, import_promises6.readFile)(gitattributesPath, "utf-8");
|
|
38124
38768
|
} catch {
|
|
38125
38769
|
}
|
|
38126
38770
|
const lines = content.split("\n");
|
|
38127
38771
|
const toAdd = GITATTRIBUTES_ENTRIES2.filter((entry) => !lines.some((line) => line.trim() === entry));
|
|
38128
38772
|
if (toAdd.length > 0) {
|
|
38129
38773
|
const suffix = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
38130
|
-
await (0,
|
|
38774
|
+
await (0, import_promises6.writeFile)(gitattributesPath, content + suffix + toAdd.join("\n") + "\n", "utf-8");
|
|
38131
38775
|
}
|
|
38132
38776
|
}
|
|
38133
38777
|
|
|
@@ -38154,7 +38798,7 @@ async function replayInit(params) {
|
|
|
38154
38798
|
if (dryRun) {
|
|
38155
38799
|
return { bootstrap: bootstrapResult, fernignoreEntries: [], gitattributesEntries: [] };
|
|
38156
38800
|
}
|
|
38157
|
-
const lockfilePath = (0,
|
|
38801
|
+
const lockfilePath = (0, import_path15.join)(repoPath, ".fern", "replay.lock");
|
|
38158
38802
|
const lockfileContent = (0, import_fs11.existsSync)(lockfilePath) ? (0, import_fs11.readFileSync)(lockfilePath, "utf-8") : void 0;
|
|
38159
38803
|
return {
|
|
38160
38804
|
bootstrap: bootstrapResult,
|
|
@@ -38275,9 +38919,9 @@ init_dist3();
|
|
|
38275
38919
|
|
|
38276
38920
|
// src/replay/replay-run.ts
|
|
38277
38921
|
init_dist3();
|
|
38278
|
-
var
|
|
38922
|
+
var import_child_process4 = require("child_process");
|
|
38279
38923
|
var import_fs12 = require("fs");
|
|
38280
|
-
var
|
|
38924
|
+
var import_path16 = require("path");
|
|
38281
38925
|
async function replayPrepare(params) {
|
|
38282
38926
|
const {
|
|
38283
38927
|
outputDir,
|
|
@@ -38288,7 +38932,7 @@ async function replayPrepare(params) {
|
|
|
38288
38932
|
skipApplication,
|
|
38289
38933
|
logger
|
|
38290
38934
|
} = params;
|
|
38291
|
-
const lockfilePath = (0,
|
|
38935
|
+
const lockfilePath = (0, import_path16.join)(outputDir, ".fern", "replay.lock");
|
|
38292
38936
|
if (!(0, import_fs12.existsSync)(lockfilePath)) {
|
|
38293
38937
|
return null;
|
|
38294
38938
|
}
|
|
@@ -38420,7 +39064,7 @@ async function replayRun(params) {
|
|
|
38420
39064
|
}
|
|
38421
39065
|
function isTagMergedIntoHead(cwd2, tagSha) {
|
|
38422
39066
|
try {
|
|
38423
|
-
(0,
|
|
39067
|
+
(0, import_child_process4.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
|
|
38424
39068
|
cwd: cwd2,
|
|
38425
39069
|
stdio: "pipe"
|
|
38426
39070
|
});
|
|
@@ -38432,7 +39076,7 @@ function isTagMergedIntoHead(cwd2, tagSha) {
|
|
|
38432
39076
|
return false;
|
|
38433
39077
|
}
|
|
38434
39078
|
try {
|
|
38435
|
-
const trees = (0,
|
|
39079
|
+
const trees = (0, import_child_process4.execFileSync)("git", ["log", "HEAD", "--format=%T", "--max-count=500"], {
|
|
38436
39080
|
cwd: cwd2,
|
|
38437
39081
|
encoding: "utf-8",
|
|
38438
39082
|
stdio: "pipe"
|
|
@@ -38444,7 +39088,7 @@ function isTagMergedIntoHead(cwd2, tagSha) {
|
|
|
38444
39088
|
}
|
|
38445
39089
|
function gitRevParse(cwd2, rev) {
|
|
38446
39090
|
try {
|
|
38447
|
-
return (0,
|
|
39091
|
+
return (0, import_child_process4.execFileSync)("git", ["rev-parse", "--verify", rev], {
|
|
38448
39092
|
cwd: cwd2,
|
|
38449
39093
|
encoding: "utf-8",
|
|
38450
39094
|
stdio: "pipe"
|
|
@@ -38455,7 +39099,7 @@ function gitRevParse(cwd2, rev) {
|
|
|
38455
39099
|
}
|
|
38456
39100
|
function gitDiffNameOnly(cwd2, from, to) {
|
|
38457
39101
|
try {
|
|
38458
|
-
const output = (0,
|
|
39102
|
+
const output = (0, import_child_process4.execFileSync)("git", ["diff", "--name-only", from, to], {
|
|
38459
39103
|
cwd: cwd2,
|
|
38460
39104
|
encoding: "utf-8",
|
|
38461
39105
|
stdio: "pipe"
|
|
@@ -38473,29 +39117,29 @@ function replayStatus(params) {
|
|
|
38473
39117
|
}
|
|
38474
39118
|
|
|
38475
39119
|
// src/configuration/loadGitHubConfig.ts
|
|
38476
|
-
var
|
|
39120
|
+
var import_promises7 = require("fs/promises");
|
|
38477
39121
|
async function loadGitHubConfig({
|
|
38478
39122
|
absolutePathToConfig
|
|
38479
39123
|
}) {
|
|
38480
|
-
const rawContents = await (0,
|
|
39124
|
+
const rawContents = await (0, import_promises7.readFile)(absolutePathToConfig, "utf8");
|
|
38481
39125
|
return JSON.parse(rawContents);
|
|
38482
39126
|
}
|
|
38483
39127
|
|
|
38484
39128
|
// src/configuration/loadReadmeConfig.ts
|
|
38485
|
-
var
|
|
39129
|
+
var import_promises8 = require("fs/promises");
|
|
38486
39130
|
async function loadReadmeConfig({
|
|
38487
39131
|
absolutePathToConfig
|
|
38488
39132
|
}) {
|
|
38489
|
-
const rawContents = await (0,
|
|
39133
|
+
const rawContents = await (0, import_promises8.readFile)(absolutePathToConfig, "utf8");
|
|
38490
39134
|
return JSON.parse(rawContents);
|
|
38491
39135
|
}
|
|
38492
39136
|
|
|
38493
39137
|
// src/configuration/loadReferenceConfig.ts
|
|
38494
|
-
var
|
|
39138
|
+
var import_promises9 = require("fs/promises");
|
|
38495
39139
|
async function loadReferenceConfig({
|
|
38496
39140
|
absolutePathToConfig
|
|
38497
39141
|
}) {
|
|
38498
|
-
const rawContents = await (0,
|
|
39142
|
+
const rawContents = await (0, import_promises9.readFile)(absolutePathToConfig, "utf8");
|
|
38499
39143
|
return JSON.parse(rawContents);
|
|
38500
39144
|
}
|
|
38501
39145
|
|
|
@@ -38512,7 +39156,7 @@ var consolePipelineLogger = {
|
|
|
38512
39156
|
};
|
|
38513
39157
|
|
|
38514
39158
|
// src/pipeline/PostGenerationPipeline.ts
|
|
38515
|
-
var
|
|
39159
|
+
var import_child_process6 = require("child_process");
|
|
38516
39160
|
|
|
38517
39161
|
// src/pipeline/github/constants.ts
|
|
38518
39162
|
var FERN_BOT_NAME2 = "fern-api";
|
|
@@ -38520,10 +39164,10 @@ var FERN_BOT_EMAIL2 = "115122769+fern-api[bot]@users.noreply.github.com";
|
|
|
38520
39164
|
var FERN_BOT_LOGIN2 = "fern-api[bot]";
|
|
38521
39165
|
|
|
38522
39166
|
// src/pipeline/steps/AutoVersionStep.ts
|
|
38523
|
-
var
|
|
39167
|
+
var import_child_process5 = require("child_process");
|
|
38524
39168
|
var import_fs14 = require("fs");
|
|
38525
|
-
var
|
|
38526
|
-
var
|
|
39169
|
+
var import_promises11 = require("fs/promises");
|
|
39170
|
+
var import_path18 = require("path");
|
|
38527
39171
|
|
|
38528
39172
|
// ../commons/logging-execa/lib/loggingExeca.js
|
|
38529
39173
|
var import_execa = __toESM(require_execa(), 1);
|
|
@@ -38582,8 +39226,8 @@ async function loggingExeca(logger, executable, args = [], { doNotPipeOutput = f
|
|
|
38582
39226
|
|
|
38583
39227
|
// src/autoversion/AutoVersioningService.ts
|
|
38584
39228
|
var import_fs13 = require("fs");
|
|
38585
|
-
var
|
|
38586
|
-
var
|
|
39229
|
+
var import_promises10 = require("fs/promises");
|
|
39230
|
+
var import_path17 = require("path");
|
|
38587
39231
|
var import_semver = __toESM(require_semver2());
|
|
38588
39232
|
var AutoVersioningException = class extends Error {
|
|
38589
39233
|
/**
|
|
@@ -39270,7 +39914,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39270
39914
|
);
|
|
39271
39915
|
return;
|
|
39272
39916
|
}
|
|
39273
|
-
const goModPath = (0,
|
|
39917
|
+
const goModPath = (0, import_path17.join)(workingDirectory, "go.mod");
|
|
39274
39918
|
if (!(0, import_fs13.existsSync)(goModPath)) {
|
|
39275
39919
|
this.logger.debug(`No go.mod found in ${workingDirectory}, skipping Go module path update`);
|
|
39276
39920
|
return;
|
|
@@ -39304,7 +39948,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39304
39948
|
* Reads the module path from a go.mod file.
|
|
39305
39949
|
*/
|
|
39306
39950
|
async readGoModulePath(goModPath) {
|
|
39307
|
-
const content = await (0,
|
|
39951
|
+
const content = await (0, import_promises10.readFile)(goModPath, "utf-8");
|
|
39308
39952
|
for (const line of content.split("\n")) {
|
|
39309
39953
|
const trimmed2 = line.trim();
|
|
39310
39954
|
if (trimmed2.startsWith("module ")) {
|
|
@@ -39317,7 +39961,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39317
39961
|
* Adds a version suffix to the module line in go.mod.
|
|
39318
39962
|
*/
|
|
39319
39963
|
async addSuffixToGoMod(goModPath, modulePath, suffix) {
|
|
39320
|
-
const content = await (0,
|
|
39964
|
+
const content = await (0, import_promises10.readFile)(goModPath, "utf-8");
|
|
39321
39965
|
const lines = content.split("\n");
|
|
39322
39966
|
let changed = false;
|
|
39323
39967
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -39329,7 +39973,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39329
39973
|
}
|
|
39330
39974
|
}
|
|
39331
39975
|
if (changed) {
|
|
39332
|
-
await (0,
|
|
39976
|
+
await (0, import_promises10.writeFile)(goModPath, lines.join("\n"), "utf-8");
|
|
39333
39977
|
this.logger.debug(`Updated go.mod: added ${suffix} to module path`);
|
|
39334
39978
|
}
|
|
39335
39979
|
}
|
|
@@ -39338,10 +39982,10 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39338
39982
|
*/
|
|
39339
39983
|
async walkDirectory(dir, filter2) {
|
|
39340
39984
|
const results = [];
|
|
39341
|
-
const entries2 = await (0,
|
|
39985
|
+
const entries2 = await (0, import_promises10.readdir)(dir);
|
|
39342
39986
|
for (const entry of entries2) {
|
|
39343
|
-
const fullPath = (0,
|
|
39344
|
-
const entryStat = await (0,
|
|
39987
|
+
const fullPath = (0, import_path17.join)(dir, entry);
|
|
39988
|
+
const entryStat = await (0, import_promises10.stat)(fullPath);
|
|
39345
39989
|
if (entryStat.isDirectory()) {
|
|
39346
39990
|
if (entry === ".git" || entry === "vendor") {
|
|
39347
39991
|
continue;
|
|
@@ -39358,7 +40002,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39358
40002
|
* Adds a version suffix to import paths in all .go files in the repository.
|
|
39359
40003
|
*/
|
|
39360
40004
|
async addSuffixToGoFiles(repoRoot, modulePath, suffix) {
|
|
39361
|
-
const goFiles = await this.walkDirectory(repoRoot, (filePath) => (0,
|
|
40005
|
+
const goFiles = await this.walkDirectory(repoRoot, (filePath) => (0, import_path17.extname)(filePath) === ".go");
|
|
39362
40006
|
for (const filePath of goFiles) {
|
|
39363
40007
|
await this.addSuffixToGoFile(filePath, modulePath, suffix);
|
|
39364
40008
|
}
|
|
@@ -39368,7 +40012,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39368
40012
|
* Replaces occurrences of the module path with modulePath + suffix in import statements.
|
|
39369
40013
|
*/
|
|
39370
40014
|
async addSuffixToGoFile(filePath, modulePath, suffix) {
|
|
39371
|
-
const content = await (0,
|
|
40015
|
+
const content = await (0, import_promises10.readFile)(filePath, "utf-8");
|
|
39372
40016
|
const lines = content.split("\n");
|
|
39373
40017
|
let changed = false;
|
|
39374
40018
|
let inImportBlock = false;
|
|
@@ -39397,7 +40041,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
39397
40041
|
}
|
|
39398
40042
|
}
|
|
39399
40043
|
if (changed) {
|
|
39400
|
-
await (0,
|
|
40044
|
+
await (0, import_promises10.writeFile)(filePath, lines.join("\n"), "utf-8");
|
|
39401
40045
|
this.logger.debug(`Updated Go imports in ${filePath}`);
|
|
39402
40046
|
}
|
|
39403
40047
|
}
|
|
@@ -39760,7 +40404,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
39760
40404
|
}
|
|
39761
40405
|
async readVersionFromMetadata() {
|
|
39762
40406
|
try {
|
|
39763
|
-
const output = (0,
|
|
40407
|
+
const output = (0, import_child_process5.execFileSync)("git", ["show", "HEAD~1:.fern/metadata.json"], {
|
|
39764
40408
|
cwd: this.outputDir,
|
|
39765
40409
|
encoding: "utf-8",
|
|
39766
40410
|
stdio: "pipe"
|
|
@@ -39776,7 +40420,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
39776
40420
|
return mappedMagicVersion.startsWith("v") ? `v${stripped}` : stripped;
|
|
39777
40421
|
}
|
|
39778
40422
|
gitDiff(from, to) {
|
|
39779
|
-
return (0,
|
|
40423
|
+
return (0, import_child_process5.execFileSync)("git", ["diff", from, to, "--", ".", ":(exclude).fern/metadata.json"], {
|
|
39780
40424
|
cwd: this.outputDir,
|
|
39781
40425
|
encoding: "utf-8",
|
|
39782
40426
|
stdio: "pipe",
|
|
@@ -39789,12 +40433,12 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
39789
40433
|
const fullMessage = body.length > 0 ? `${COMMIT_MARKER} ${subject}
|
|
39790
40434
|
|
|
39791
40435
|
${body}` : `${COMMIT_MARKER} ${subject}`;
|
|
39792
|
-
(0,
|
|
39793
|
-
(0,
|
|
40436
|
+
(0, import_child_process5.execFileSync)("git", ["add", "-A"], { cwd: this.outputDir, stdio: "pipe" });
|
|
40437
|
+
(0, import_child_process5.execFileSync)("git", ["commit", "--allow-empty", "-m", fullMessage], {
|
|
39794
40438
|
cwd: this.outputDir,
|
|
39795
40439
|
stdio: "pipe"
|
|
39796
40440
|
});
|
|
39797
|
-
return (0,
|
|
40441
|
+
return (0, import_child_process5.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
39798
40442
|
cwd: this.outputDir,
|
|
39799
40443
|
encoding: "utf-8",
|
|
39800
40444
|
stdio: "pipe"
|
|
@@ -39802,7 +40446,7 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
|
|
|
39802
40446
|
}
|
|
39803
40447
|
async prependChangelogEntry(params) {
|
|
39804
40448
|
const { version: version2, entry } = params;
|
|
39805
|
-
const changelogPath = (0,
|
|
40449
|
+
const changelogPath = (0, import_path18.join)(this.outputDir, "changelog.md");
|
|
39806
40450
|
const now = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
39807
40451
|
const header = `## [${version2}] - ${now}
|
|
39808
40452
|
`;
|
|
@@ -39811,7 +40455,7 @@ ${body}` : `${COMMIT_MARKER} ${subject}`;
|
|
|
39811
40455
|
`;
|
|
39812
40456
|
let existing = "";
|
|
39813
40457
|
if ((0, import_fs14.existsSync)(changelogPath)) {
|
|
39814
|
-
existing = await (0,
|
|
40458
|
+
existing = await (0, import_promises11.readFile)(changelogPath, "utf-8");
|
|
39815
40459
|
}
|
|
39816
40460
|
let output;
|
|
39817
40461
|
if (existing.trim().length === 0) {
|
|
@@ -39828,7 +40472,7 @@ ${newBlock}${remainder}`;
|
|
|
39828
40472
|
} else {
|
|
39829
40473
|
output = `${newBlock}${existing}`;
|
|
39830
40474
|
}
|
|
39831
|
-
await (0,
|
|
40475
|
+
await (0, import_promises11.writeFile)(changelogPath, output, "utf-8");
|
|
39832
40476
|
}
|
|
39833
40477
|
brandMessage(message) {
|
|
39834
40478
|
if (this.config.isWhitelabel) {
|
|
@@ -40010,8 +40654,8 @@ var GenerationCommitStep = class extends BaseStep {
|
|
|
40010
40654
|
};
|
|
40011
40655
|
|
|
40012
40656
|
// src/pipeline/steps/GithubStep.ts
|
|
40013
|
-
var
|
|
40014
|
-
var
|
|
40657
|
+
var import_promises12 = require("fs/promises");
|
|
40658
|
+
var import_path19 = require("path");
|
|
40015
40659
|
|
|
40016
40660
|
// src/pipeline/github/createReplayBranch.ts
|
|
40017
40661
|
async function createReplayBranch(repository, branchName, commitMessage, replayConflictInfo, logger) {
|
|
@@ -40628,13 +41272,13 @@ var GithubStep = class extends BaseStep {
|
|
|
40628
41272
|
}
|
|
40629
41273
|
async ensureFernignore() {
|
|
40630
41274
|
this.logger.debug("Checking for .fernignore file...");
|
|
40631
|
-
const fernignorePath = (0,
|
|
41275
|
+
const fernignorePath = (0, import_path19.join)(this.outputDir, ".fernignore");
|
|
40632
41276
|
try {
|
|
40633
|
-
await (0,
|
|
41277
|
+
await (0, import_promises12.access)(fernignorePath);
|
|
40634
41278
|
this.logger.debug(".fernignore already exists");
|
|
40635
41279
|
} catch {
|
|
40636
41280
|
this.logger.debug("Creating .fernignore file...");
|
|
40637
|
-
await (0,
|
|
41281
|
+
await (0, import_promises12.writeFile)(fernignorePath, "# Specify files that shouldn't be modified by Fern\n", "utf-8");
|
|
40638
41282
|
}
|
|
40639
41283
|
}
|
|
40640
41284
|
deriveSkipCommit(replayResult) {
|
|
@@ -40856,8 +41500,8 @@ var PostGenerationPipeline = class {
|
|
|
40856
41500
|
async run() {
|
|
40857
41501
|
if (this.config.github?.enabled) {
|
|
40858
41502
|
try {
|
|
40859
|
-
(0,
|
|
40860
|
-
(0,
|
|
41503
|
+
(0, import_child_process6.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
|
|
41504
|
+
(0, import_child_process6.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
|
|
40861
41505
|
} catch {
|
|
40862
41506
|
}
|
|
40863
41507
|
}
|
|
@@ -40927,7 +41571,7 @@ void yargs_default(hideBin(process.argv)).scriptName(process.env.CLI_NAME ?? "ge
|
|
|
40927
41571
|
const readmeConfig = await loadReadmeConfig({
|
|
40928
41572
|
absolutePathToConfig: resolve(wd, argv.config)
|
|
40929
41573
|
});
|
|
40930
|
-
const originalReadmeContent = argv.originalReadme != null ? await (0,
|
|
41574
|
+
const originalReadmeContent = argv.originalReadme != null ? await (0, import_promises13.readFile)(argv.originalReadme, "utf8") : void 0;
|
|
40931
41575
|
await generateReadmeToStream({
|
|
40932
41576
|
originalReadmeContent,
|
|
40933
41577
|
readmeConfig,
|
|
@@ -41055,7 +41699,7 @@ void yargs_default(hideBin(process.argv)).scriptName(process.env.CLI_NAME ?? "ge
|
|
|
41055
41699
|
try {
|
|
41056
41700
|
const wd = cwd();
|
|
41057
41701
|
const configValue = argv.config;
|
|
41058
|
-
const configContent = configValue === STDIN_MARKER ? await readStdin() : configValue.trimStart().startsWith("{") ? configValue : await (0,
|
|
41702
|
+
const configContent = configValue === STDIN_MARKER ? await readStdin() : configValue.trimStart().startsWith("{") ? configValue : await (0, import_promises13.readFile)(resolve(wd, configValue), "utf-8");
|
|
41059
41703
|
let config;
|
|
41060
41704
|
try {
|
|
41061
41705
|
config = JSON.parse(configContent);
|
|
@@ -41351,7 +41995,7 @@ async function createWriteStream(outputPath) {
|
|
|
41351
41995
|
}
|
|
41352
41996
|
async function createWriteStreamFromFile(filepath) {
|
|
41353
41997
|
if (!await doesPathExist(filepath)) {
|
|
41354
|
-
await (0,
|
|
41998
|
+
await (0, import_promises13.mkdir)(import_path20.default.dirname(filepath), { recursive: true });
|
|
41355
41999
|
}
|
|
41356
42000
|
return import_fs15.default.createWriteStream(filepath);
|
|
41357
42001
|
}
|