@fern-api/generator-cli 0.9.25 → 0.9.26
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 +133 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -22126,7 +22126,7 @@ var init_diff3 = __esm({
|
|
|
22126
22126
|
}
|
|
22127
22127
|
});
|
|
22128
22128
|
|
|
22129
|
-
// ../../node_modules/.pnpm/@fern-api+replay@0.
|
|
22129
|
+
// ../../node_modules/.pnpm/@fern-api+replay@0.15.0/node_modules/@fern-api/replay/dist/index.js
|
|
22130
22130
|
var dist_exports = {};
|
|
22131
22131
|
__export(dist_exports, {
|
|
22132
22132
|
CREDENTIAL_PATTERNS: () => CREDENTIAL_PATTERNS,
|
|
@@ -23630,7 +23630,7 @@ function status(outputDir) {
|
|
|
23630
23630
|
}
|
|
23631
23631
|
var import_promises3, import_os, import_path7, import_fs6, import_path8, import_yaml, import_crypto, import_promises4, import_os2, import_path9, import_fs7, import_promises5, import_path10, import_promises6, import_os3, import_path11, import_child_process3, import_crypto2, import_fs8, import_path12, import_yaml2, import_crypto3, import_fs9, import_path13, import_fs10, import_promises7, import_path14, __defProp3, __getOwnPropNames3, __esm3, __export3, GitClient_exports, GitClient, init_GitClient, HybridReconstruction_exports, init_HybridReconstruction, PatchApplyTheirs_exports, init_PatchApplyTheirs, CREDENTIAL_PATTERNS, SENSITIVE_FILE_PATTERNS, FERN_BOT_NAME, FERN_BOT_EMAIL, FERN_BOT_LOGIN, FERN_SUPPORT_NAMES, LOCKFILE_HEADER, LockfileNotFoundError, LockfileManager, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, BINARY_EXTENSIONS, ReplayApplicator, INFRASTRUCTURE_FILES, ReplayDetector, ReplayCommitter, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
|
|
23632
23632
|
var init_dist3 = __esm({
|
|
23633
|
-
"../../node_modules/.pnpm/@fern-api+replay@0.
|
|
23633
|
+
"../../node_modules/.pnpm/@fern-api+replay@0.15.0/node_modules/@fern-api/replay/dist/index.js"() {
|
|
23634
23634
|
"use strict";
|
|
23635
23635
|
init_esm4();
|
|
23636
23636
|
import_promises3 = require("fs/promises");
|
|
@@ -26243,6 +26243,66 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
26243
26243
|
}
|
|
26244
26244
|
return snapshot;
|
|
26245
26245
|
}
|
|
26246
|
+
/**
|
|
26247
|
+
* FER-10203: returns true when a `[fern-autoversion]` commit between
|
|
26248
|
+
* `fromSha` and `toSha` touched any of the patch's `files`. Re-classifies
|
|
26249
|
+
* each grep match via `isGenerationCommit` so a customer commit that
|
|
26250
|
+
* merely quotes the marker in its body doesn't false-positive.
|
|
26251
|
+
*/
|
|
26252
|
+
async hasAutoversionContamination(fromSha, toSha, files) {
|
|
26253
|
+
if (files.length === 0) return false;
|
|
26254
|
+
const log = await this.git.exec([
|
|
26255
|
+
"log",
|
|
26256
|
+
`${fromSha}..${toSha}`,
|
|
26257
|
+
"--grep=\\[fern-autoversion\\]",
|
|
26258
|
+
"--extended-regexp",
|
|
26259
|
+
"--format=%H%x09%aN%x09%ae%x09%s",
|
|
26260
|
+
"--",
|
|
26261
|
+
...files
|
|
26262
|
+
]).catch(() => "");
|
|
26263
|
+
if (!log.trim()) return false;
|
|
26264
|
+
for (const line of log.trim().split("\n")) {
|
|
26265
|
+
const [sha, authorName, authorEmail, message] = line.split(" ");
|
|
26266
|
+
if (sha == null) continue;
|
|
26267
|
+
if (isGenerationCommit({
|
|
26268
|
+
sha,
|
|
26269
|
+
authorName: authorName ?? "",
|
|
26270
|
+
authorEmail: authorEmail ?? "",
|
|
26271
|
+
message: message ?? ""
|
|
26272
|
+
})) {
|
|
26273
|
+
return true;
|
|
26274
|
+
}
|
|
26275
|
+
}
|
|
26276
|
+
return false;
|
|
26277
|
+
}
|
|
26278
|
+
/**
|
|
26279
|
+
* FER-10203: rebuild patch_content from `theirs_snapshot` (captured at
|
|
26280
|
+
* detection time, predates pipeline content) rather than a HEAD-relative
|
|
26281
|
+
* diff. Returns `null` when snapshot is missing or doesn't cover every
|
|
26282
|
+
* file in `patch.files` — caller leaves the patch unchanged.
|
|
26283
|
+
*/
|
|
26284
|
+
async computeSnapshotBasedPatchDiff(patch, currentGen) {
|
|
26285
|
+
if (!patch.theirs_snapshot) return null;
|
|
26286
|
+
if (Object.keys(patch.theirs_snapshot).length === 0) return null;
|
|
26287
|
+
for (const file of patch.files) {
|
|
26288
|
+
if (patch.theirs_snapshot[file] == null) return null;
|
|
26289
|
+
}
|
|
26290
|
+
const fragments = [];
|
|
26291
|
+
for (const file of patch.files) {
|
|
26292
|
+
const theirsContent = patch.theirs_snapshot[file];
|
|
26293
|
+
const oursContent = await this.git.showFile(currentGen, file).catch(() => null);
|
|
26294
|
+
if (oursContent == null) {
|
|
26295
|
+
fragments.push(synthesizeNewFileDiff(file, theirsContent));
|
|
26296
|
+
continue;
|
|
26297
|
+
}
|
|
26298
|
+
if (oursContent === theirsContent) continue;
|
|
26299
|
+
const fileDiff = await unifiedDiff(oursContent, theirsContent, file);
|
|
26300
|
+
if (fileDiff.trim()) {
|
|
26301
|
+
fragments.push(fileDiff);
|
|
26302
|
+
}
|
|
26303
|
+
}
|
|
26304
|
+
return fragments.join("");
|
|
26305
|
+
}
|
|
26246
26306
|
/**
|
|
26247
26307
|
* Read THEIRS snapshot from a git tree-ish (commit, branch, or tree).
|
|
26248
26308
|
* Used when the diff that produced `patch_content` was relative to that
|
|
@@ -26508,6 +26568,41 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
26508
26568
|
}
|
|
26509
26569
|
if (patch.base_generation === currentGen) {
|
|
26510
26570
|
try {
|
|
26571
|
+
const contaminated = await this.hasAutoversionContamination(
|
|
26572
|
+
currentGen,
|
|
26573
|
+
"HEAD",
|
|
26574
|
+
patch.files
|
|
26575
|
+
);
|
|
26576
|
+
if (contaminated) {
|
|
26577
|
+
const snapshotDiff = await this.computeSnapshotBasedPatchDiff(
|
|
26578
|
+
patch,
|
|
26579
|
+
currentGen
|
|
26580
|
+
);
|
|
26581
|
+
if (snapshotDiff === null) continue;
|
|
26582
|
+
if (!snapshotDiff.trim()) {
|
|
26583
|
+
if (await allPatchFilesUserOwned(patch)) continue;
|
|
26584
|
+
this.lockManager.removePatch(patch.id);
|
|
26585
|
+
contentRefreshed++;
|
|
26586
|
+
continue;
|
|
26587
|
+
}
|
|
26588
|
+
const snapHasStaleMarkers = snapshotDiff.split("\n").some(
|
|
26589
|
+
(l) => l.startsWith("+<<<<<<< Generated") || l.startsWith("+>>>>>>> Your customization")
|
|
26590
|
+
);
|
|
26591
|
+
if (snapHasStaleMarkers) continue;
|
|
26592
|
+
const isProtectedSnap = patch.files.some(
|
|
26593
|
+
(file) => file === ".fernignore" || fernignorePatterns.some((p2) => file === p2 || minimatch(file, p2))
|
|
26594
|
+
);
|
|
26595
|
+
if (isProtectedSnap) continue;
|
|
26596
|
+
const snapHash = this.detector.computeContentHash(snapshotDiff);
|
|
26597
|
+
if (snapHash !== patch.content_hash) {
|
|
26598
|
+
this.lockManager.updatePatch(patch.id, {
|
|
26599
|
+
patch_content: snapshotDiff,
|
|
26600
|
+
content_hash: snapHash
|
|
26601
|
+
});
|
|
26602
|
+
contentRefreshed++;
|
|
26603
|
+
}
|
|
26604
|
+
continue;
|
|
26605
|
+
}
|
|
26511
26606
|
const ppResult = await computePerPatchDiffWithFallback(
|
|
26512
26607
|
patch,
|
|
26513
26608
|
(f) => this.git.showFile(currentGen, f),
|
|
@@ -26559,6 +26654,42 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
26559
26654
|
try {
|
|
26560
26655
|
const markerFiles = await this.git.exec(["grep", "-l", "<<<<<<< Generated", "HEAD", "--", ...patch.files]).catch(() => "");
|
|
26561
26656
|
if (markerFiles.trim()) continue;
|
|
26657
|
+
const contaminated = await this.hasAutoversionContamination(
|
|
26658
|
+
currentGen,
|
|
26659
|
+
"HEAD",
|
|
26660
|
+
patch.files
|
|
26661
|
+
);
|
|
26662
|
+
if (contaminated) {
|
|
26663
|
+
const snapshotDiff = await this.computeSnapshotBasedPatchDiff(
|
|
26664
|
+
patch,
|
|
26665
|
+
currentGen
|
|
26666
|
+
);
|
|
26667
|
+
if (snapshotDiff === null) continue;
|
|
26668
|
+
if (!snapshotDiff.trim()) {
|
|
26669
|
+
if (await allPatchFilesUserOwned(patch)) {
|
|
26670
|
+
try {
|
|
26671
|
+
this.lockManager.updatePatch(patch.id, { base_generation: currentGen });
|
|
26672
|
+
} catch {
|
|
26673
|
+
}
|
|
26674
|
+
continue;
|
|
26675
|
+
}
|
|
26676
|
+
this.lockManager.removePatch(patch.id);
|
|
26677
|
+
conflictAbsorbed++;
|
|
26678
|
+
continue;
|
|
26679
|
+
}
|
|
26680
|
+
const snapHasStaleMarkers = snapshotDiff.split("\n").some(
|
|
26681
|
+
(l) => l.startsWith("+<<<<<<< Generated") || l.startsWith("+>>>>>>> Your customization")
|
|
26682
|
+
);
|
|
26683
|
+
if (snapHasStaleMarkers) continue;
|
|
26684
|
+
const snapHash = this.detector.computeContentHash(snapshotDiff);
|
|
26685
|
+
this.lockManager.updatePatch(patch.id, {
|
|
26686
|
+
base_generation: currentGen,
|
|
26687
|
+
patch_content: snapshotDiff,
|
|
26688
|
+
content_hash: snapHash
|
|
26689
|
+
});
|
|
26690
|
+
conflictResolved++;
|
|
26691
|
+
continue;
|
|
26692
|
+
}
|
|
26562
26693
|
const ppResult = await computePerPatchDiffWithFallback(
|
|
26563
26694
|
patch,
|
|
26564
26695
|
(f) => this.git.showFile(currentGen, f),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fern-api/generator-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.26",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fern-api/fern.git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@boundaryml/baml": "^0.219.0",
|
|
26
|
-
"@fern-api/replay": "0.
|
|
26
|
+
"@fern-api/replay": "0.15.0",
|
|
27
27
|
"@octokit/rest": "^22.0.1",
|
|
28
28
|
"es-toolkit": "^1.45.1",
|
|
29
29
|
"semver": "^7.6.3",
|