@fern-api/generator-cli 0.9.30 → 0.9.32
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/api.d.ts +0 -2
- package/dist/api.js +3 -134
- package/dist/cli.js +118 -298
- package/package.json +2 -2
package/dist/api.d.ts
CHANGED
|
@@ -580,8 +580,6 @@ interface ReplayRunResult {
|
|
|
580
580
|
previousGenerationSha: string | null;
|
|
581
581
|
/** SHA of the [fern-generated] commit created by this replay run (null if replay didn't run or unreadable) */
|
|
582
582
|
currentGenerationSha: string | null;
|
|
583
|
-
/** SHA of main's HEAD before replay ran. Always on main's lineage, stable after squash merges. */
|
|
584
|
-
baseBranchHead: string | null;
|
|
585
583
|
/** True when this run inlined `bootstrap()` to create the lockfile (auto-init from `fern generate`). */
|
|
586
584
|
autoBootstrapped: boolean;
|
|
587
585
|
/**
|
package/dist/api.js
CHANGED
|
@@ -10356,19 +10356,10 @@ async function replayResolve(params) {
|
|
|
10356
10356
|
|
|
10357
10357
|
// src/replay/replay-run.ts
|
|
10358
10358
|
var import_replay4 = require("@fern-api/replay");
|
|
10359
|
-
var import_child_process3 = require("child_process");
|
|
10360
10359
|
var import_fs3 = require("fs");
|
|
10361
10360
|
var import_path5 = require("path");
|
|
10362
10361
|
async function replayPrepare(params, state) {
|
|
10363
|
-
const {
|
|
10364
|
-
outputDir,
|
|
10365
|
-
cliVersion,
|
|
10366
|
-
generatorVersions,
|
|
10367
|
-
stageOnly = false,
|
|
10368
|
-
generatorName,
|
|
10369
|
-
skipApplication,
|
|
10370
|
-
logger
|
|
10371
|
-
} = params;
|
|
10362
|
+
const { outputDir, cliVersion, generatorVersions, stageOnly = false, skipApplication, logger } = params;
|
|
10372
10363
|
const lockfilePath = (0, import_path5.join)(outputDir, ".fern", "replay.lock");
|
|
10373
10364
|
let autoBootstrapped = false;
|
|
10374
10365
|
let bootstrapAttempted = false;
|
|
@@ -10401,63 +10392,6 @@ async function replayPrepare(params, state) {
|
|
|
10401
10392
|
return null;
|
|
10402
10393
|
}
|
|
10403
10394
|
}
|
|
10404
|
-
const baseBranchHead = gitRevParse(outputDir, "HEAD");
|
|
10405
|
-
let previousGenerationSha = null;
|
|
10406
|
-
let prevBaseBranchHead = null;
|
|
10407
|
-
try {
|
|
10408
|
-
const lockManager = new import_replay4.LockfileManager(outputDir);
|
|
10409
|
-
if (lockManager.exists()) {
|
|
10410
|
-
const lock = lockManager.read();
|
|
10411
|
-
previousGenerationSha = lock.current_generation;
|
|
10412
|
-
const latestGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);
|
|
10413
|
-
prevBaseBranchHead = latestGen?.base_branch_head ?? null;
|
|
10414
|
-
}
|
|
10415
|
-
} catch {
|
|
10416
|
-
}
|
|
10417
|
-
if (previousGenerationSha != null) {
|
|
10418
|
-
const sanitizedName = generatorName?.replace(/\//g, "--");
|
|
10419
|
-
const namespacedTag = sanitizedName != null ? `fern-generation-base--${sanitizedName}` : null;
|
|
10420
|
-
const tagSha = (namespacedTag != null ? gitRevParse(outputDir, namespacedTag) : null) ?? gitRevParse(outputDir, "fern-generation-base");
|
|
10421
|
-
let shouldSync = false;
|
|
10422
|
-
if (tagSha != null) {
|
|
10423
|
-
const tagParent = gitRevParse(outputDir, `${tagSha}^`);
|
|
10424
|
-
if (tagParent === prevBaseBranchHead || tagParent === previousGenerationSha) {
|
|
10425
|
-
const tagDistance = gitDiffNameOnly(outputDir, tagSha, "HEAD").length;
|
|
10426
|
-
const lockDistance = gitDiffNameOnly(
|
|
10427
|
-
outputDir,
|
|
10428
|
-
prevBaseBranchHead ?? previousGenerationSha,
|
|
10429
|
-
"HEAD"
|
|
10430
|
-
).length;
|
|
10431
|
-
shouldSync = tagDistance < lockDistance;
|
|
10432
|
-
}
|
|
10433
|
-
}
|
|
10434
|
-
if (shouldSync && tagSha != null) {
|
|
10435
|
-
if (!isTagMergedIntoHead(outputDir, tagSha)) {
|
|
10436
|
-
logger?.warn(
|
|
10437
|
-
`fern-generation-base tag ${tagSha} is not reachable from HEAD \u2014 skipping divergent-merge sync. The tag likely points at an unmerged generation (PR closed without merge).`
|
|
10438
|
-
);
|
|
10439
|
-
} else {
|
|
10440
|
-
try {
|
|
10441
|
-
const syncService = new import_replay4.ReplayService(outputDir, { enabled: true });
|
|
10442
|
-
await syncService.syncFromDivergentMerge(tagSha, {
|
|
10443
|
-
cliVersion,
|
|
10444
|
-
generatorVersions,
|
|
10445
|
-
baseBranchHead: baseBranchHead ?? void 0
|
|
10446
|
-
});
|
|
10447
|
-
} catch (error) {
|
|
10448
|
-
logger?.warn("Replay divergent-merge sync failed, continuing without sync: " + String(error));
|
|
10449
|
-
throw new ReplayPrepareError(String(error), error);
|
|
10450
|
-
}
|
|
10451
|
-
try {
|
|
10452
|
-
const freshLockManager = new import_replay4.LockfileManager(outputDir);
|
|
10453
|
-
if (freshLockManager.exists()) {
|
|
10454
|
-
previousGenerationSha = freshLockManager.read().current_generation;
|
|
10455
|
-
}
|
|
10456
|
-
} catch {
|
|
10457
|
-
}
|
|
10458
|
-
}
|
|
10459
|
-
}
|
|
10460
|
-
}
|
|
10461
10395
|
const service = new import_replay4.ReplayService(outputDir, { enabled: true });
|
|
10462
10396
|
let preparation;
|
|
10463
10397
|
try {
|
|
@@ -10465,8 +10399,7 @@ async function replayPrepare(params, state) {
|
|
|
10465
10399
|
cliVersion,
|
|
10466
10400
|
generatorVersions,
|
|
10467
10401
|
stageOnly,
|
|
10468
|
-
skipApplication
|
|
10469
|
-
baseBranchHead: baseBranchHead ?? void 0
|
|
10402
|
+
skipApplication
|
|
10470
10403
|
});
|
|
10471
10404
|
} catch (error) {
|
|
10472
10405
|
logger?.warn("Replay prepare failed, continuing without replay: " + String(error));
|
|
@@ -10477,9 +10410,8 @@ async function replayPrepare(params, state) {
|
|
|
10477
10410
|
_preparation: preparation,
|
|
10478
10411
|
outputDir,
|
|
10479
10412
|
flow: preparation.flow,
|
|
10480
|
-
previousGenerationSha,
|
|
10413
|
+
previousGenerationSha: preparation.previousGenerationSha,
|
|
10481
10414
|
currentGenerationSha: preparation.currentGenerationSha,
|
|
10482
|
-
baseBranchHead,
|
|
10483
10415
|
autoBootstrapped,
|
|
10484
10416
|
bootstrapAttempted
|
|
10485
10417
|
};
|
|
@@ -10496,24 +10428,11 @@ async function replayApply(prepared, params = {}) {
|
|
|
10496
10428
|
fernignoreUpdated: false,
|
|
10497
10429
|
previousGenerationSha: prepared.previousGenerationSha,
|
|
10498
10430
|
currentGenerationSha: prepared.currentGenerationSha,
|
|
10499
|
-
baseBranchHead: prepared.baseBranchHead,
|
|
10500
10431
|
autoBootstrapped: prepared.autoBootstrapped,
|
|
10501
10432
|
bootstrapAttempted: prepared.bootstrapAttempted,
|
|
10502
10433
|
failureReason: String(error)
|
|
10503
10434
|
};
|
|
10504
10435
|
}
|
|
10505
|
-
let resolvedBaseBranchHead = prepared.baseBranchHead;
|
|
10506
|
-
try {
|
|
10507
|
-
const freshLockManager = new import_replay4.LockfileManager(prepared.outputDir);
|
|
10508
|
-
if (freshLockManager.exists()) {
|
|
10509
|
-
const freshLock = freshLockManager.read();
|
|
10510
|
-
const latestGen = freshLock.generations.find((g) => g.commit_sha === freshLock.current_generation);
|
|
10511
|
-
if (latestGen?.base_branch_head) {
|
|
10512
|
-
resolvedBaseBranchHead = latestGen.base_branch_head;
|
|
10513
|
-
}
|
|
10514
|
-
}
|
|
10515
|
-
} catch {
|
|
10516
|
-
}
|
|
10517
10436
|
const fernignoreUpdated = await ensureReplayFernignoreEntries(prepared.outputDir);
|
|
10518
10437
|
await ensureGitattributesEntries(prepared.outputDir);
|
|
10519
10438
|
return {
|
|
@@ -10521,7 +10440,6 @@ async function replayApply(prepared, params = {}) {
|
|
|
10521
10440
|
fernignoreUpdated,
|
|
10522
10441
|
previousGenerationSha: prepared.previousGenerationSha,
|
|
10523
10442
|
currentGenerationSha: prepared.currentGenerationSha,
|
|
10524
|
-
baseBranchHead: resolvedBaseBranchHead,
|
|
10525
10443
|
autoBootstrapped: prepared.autoBootstrapped,
|
|
10526
10444
|
bootstrapAttempted: prepared.bootstrapAttempted
|
|
10527
10445
|
};
|
|
@@ -10537,7 +10455,6 @@ async function replayRun(params) {
|
|
|
10537
10455
|
fernignoreUpdated: false,
|
|
10538
10456
|
previousGenerationSha: null,
|
|
10539
10457
|
currentGenerationSha: null,
|
|
10540
|
-
baseBranchHead: null,
|
|
10541
10458
|
autoBootstrapped: false,
|
|
10542
10459
|
bootstrapAttempted: prepareState.bootstrapAttempted,
|
|
10543
10460
|
failureReason: error instanceof ReplayPrepareError ? error.reason : String(error)
|
|
@@ -10549,7 +10466,6 @@ async function replayRun(params) {
|
|
|
10549
10466
|
fernignoreUpdated: false,
|
|
10550
10467
|
previousGenerationSha: null,
|
|
10551
10468
|
currentGenerationSha: null,
|
|
10552
|
-
baseBranchHead: null,
|
|
10553
10469
|
autoBootstrapped: false,
|
|
10554
10470
|
bootstrapAttempted: prepareState.bootstrapAttempted
|
|
10555
10471
|
};
|
|
@@ -10568,53 +10484,6 @@ var ReplayPrepareError = class extends Error {
|
|
|
10568
10484
|
this.reason = reason;
|
|
10569
10485
|
}
|
|
10570
10486
|
};
|
|
10571
|
-
function isTagMergedIntoHead(cwd2, tagSha) {
|
|
10572
|
-
try {
|
|
10573
|
-
(0, import_child_process3.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
|
|
10574
|
-
cwd: cwd2,
|
|
10575
|
-
stdio: "pipe"
|
|
10576
|
-
});
|
|
10577
|
-
return true;
|
|
10578
|
-
} catch {
|
|
10579
|
-
}
|
|
10580
|
-
const tagTree = gitRevParse(cwd2, `${tagSha}^{tree}`);
|
|
10581
|
-
if (tagTree == null) {
|
|
10582
|
-
return false;
|
|
10583
|
-
}
|
|
10584
|
-
try {
|
|
10585
|
-
const trees = (0, import_child_process3.execFileSync)("git", ["log", "HEAD", "--format=%T", "--max-count=500"], {
|
|
10586
|
-
cwd: cwd2,
|
|
10587
|
-
encoding: "utf-8",
|
|
10588
|
-
stdio: "pipe"
|
|
10589
|
-
});
|
|
10590
|
-
return trees.split("\n").some((t2) => t2.trim() === tagTree);
|
|
10591
|
-
} catch {
|
|
10592
|
-
return false;
|
|
10593
|
-
}
|
|
10594
|
-
}
|
|
10595
|
-
function gitRevParse(cwd2, rev) {
|
|
10596
|
-
try {
|
|
10597
|
-
return (0, import_child_process3.execFileSync)("git", ["rev-parse", "--verify", rev], {
|
|
10598
|
-
cwd: cwd2,
|
|
10599
|
-
encoding: "utf-8",
|
|
10600
|
-
stdio: "pipe"
|
|
10601
|
-
}).trim();
|
|
10602
|
-
} catch {
|
|
10603
|
-
return null;
|
|
10604
|
-
}
|
|
10605
|
-
}
|
|
10606
|
-
function gitDiffNameOnly(cwd2, from, to) {
|
|
10607
|
-
try {
|
|
10608
|
-
const output = (0, import_child_process3.execFileSync)("git", ["diff", "--name-only", from, to], {
|
|
10609
|
-
cwd: cwd2,
|
|
10610
|
-
encoding: "utf-8",
|
|
10611
|
-
stdio: "pipe"
|
|
10612
|
-
});
|
|
10613
|
-
return output.trim().split("\n").filter(Boolean);
|
|
10614
|
-
} catch {
|
|
10615
|
-
return [];
|
|
10616
|
-
}
|
|
10617
|
-
}
|
|
10618
10487
|
|
|
10619
10488
|
// src/replay/replay-status.ts
|
|
10620
10489
|
var import_replay5 = require("@fern-api/replay");
|
package/dist/cli.js
CHANGED
|
@@ -2021,7 +2021,7 @@ var init_esm = __esm({
|
|
|
2021
2021
|
}
|
|
2022
2022
|
});
|
|
2023
2023
|
|
|
2024
|
-
// ../../node_modules/.pnpm/brace-expansion@5.0.
|
|
2024
|
+
// ../../node_modules/.pnpm/brace-expansion@5.0.6/node_modules/brace-expansion/dist/esm/index.js
|
|
2025
2025
|
function numeric(str) {
|
|
2026
2026
|
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
|
2027
2027
|
}
|
|
@@ -2124,7 +2124,7 @@ function expand_(str, max, isTop) {
|
|
|
2124
2124
|
}
|
|
2125
2125
|
const pad = n.some(isPadded);
|
|
2126
2126
|
N2 = [];
|
|
2127
|
-
for (let i2 = x2; test(i2, y2); i2 += incr) {
|
|
2127
|
+
for (let i2 = x2; test(i2, y2) && N2.length < max; i2 += incr) {
|
|
2128
2128
|
let c3;
|
|
2129
2129
|
if (isAlphaSequence) {
|
|
2130
2130
|
c3 = String.fromCharCode(i2);
|
|
@@ -2166,7 +2166,7 @@ function expand_(str, max, isTop) {
|
|
|
2166
2166
|
}
|
|
2167
2167
|
var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern, EXPANSION_MAX;
|
|
2168
2168
|
var init_esm2 = __esm({
|
|
2169
|
-
"../../node_modules/.pnpm/brace-expansion@5.0.
|
|
2169
|
+
"../../node_modules/.pnpm/brace-expansion@5.0.6/node_modules/brace-expansion/dist/esm/index.js"() {
|
|
2170
2170
|
"use strict";
|
|
2171
2171
|
init_esm();
|
|
2172
2172
|
escSlash = "\0SLASH" + Math.random() + "\0";
|
|
@@ -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.16.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,
|
|
@@ -22451,9 +22451,22 @@ function isGenerationCommit(commit) {
|
|
|
22451
22451
|
const hasGenerationMarker = commit.message.startsWith("[fern-generated]") || commit.message.startsWith("[fern-replay]") || commit.message.startsWith("[fern-autoversion]") || commit.message.includes("Generated by Fern") || commit.message.includes("\u{1F916} Generated with Fern") || // Squash merge of a Fern-generated PR uses the PR title as commit message.
|
|
22452
22452
|
// The default PR title is "SDK Generation" (from GithubStep's commitMessage default).
|
|
22453
22453
|
// GitHub appends "(#N)" for the PR number, e.g. "SDK Generation (#70)".
|
|
22454
|
-
commit.message.startsWith("SDK Generation")
|
|
22454
|
+
commit.message.startsWith("SDK Generation") || // Merge commit (GitHub's "Create a merge commit" option) of a fern-bot
|
|
22455
|
+
// regen PR. First-parent walking lands on this commit, not on the
|
|
22456
|
+
// generation commit on the side branch, so the classifier must treat
|
|
22457
|
+
// it as a generation boundary. GitHub's default subject is
|
|
22458
|
+
// "Merge pull request #N from <owner>/<branch>"; fern-bot branches are
|
|
22459
|
+
// named "<owner>/fern-bot/<...>".
|
|
22460
|
+
/^Merge pull request #\d+ from [^/]+\/fern-bot\//.test(commit.message);
|
|
22455
22461
|
return isBotAuthor || hasGenerationMarker;
|
|
22456
22462
|
}
|
|
22463
|
+
function isGenerationBoundary(commit) {
|
|
22464
|
+
const isFernSupport = FERN_SUPPORT_NAMES.includes(commit.authorName);
|
|
22465
|
+
const isBotAuthor = !isFernSupport && (commit.authorLogin === FERN_BOT_LOGIN || commit.authorEmail === FERN_BOT_EMAIL || commit.authorName === FERN_BOT_NAME);
|
|
22466
|
+
const isAutoversion = commit.message.startsWith("[fern-autoversion]");
|
|
22467
|
+
const hasBoundaryMarker = commit.message.startsWith("[fern-generated]") || commit.message.startsWith("[fern-replay]") || commit.message.includes("Generated by Fern") || commit.message.includes("\u{1F916} Generated with Fern") || commit.message.startsWith("SDK Generation");
|
|
22468
|
+
return isBotAuthor && !isAutoversion || hasBoundaryMarker;
|
|
22469
|
+
}
|
|
22457
22470
|
function isReplayCommit(commit) {
|
|
22458
22471
|
return commit.message.startsWith("[fern-replay]");
|
|
22459
22472
|
}
|
|
@@ -23934,7 +23947,7 @@ function status(outputDir) {
|
|
|
23934
23947
|
}
|
|
23935
23948
|
var import_promises3, import_os, import_path7, import_fs6, import_path8, import_yaml, import_crypto, import_path9, import_promises4, import_os2, import_path10, import_promises5, import_path11, import_promises6, import_path12, import_fs7, import_promises7, import_path13, import_promises8, import_os3, import_path14, import_child_process3, import_crypto2, import_fs8, import_path15, import_yaml2, import_crypto3, import_fs9, import_path16, import_fs10, import_promises9, import_path17, __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, BINARY_EXTENSIONS, INFRASTRUCTURE_FILES, ReplayDetector, MergeAccumulator, CONFLICT_OPENER, CONFLICT_SEPARATOR, CONFLICT_CLOSER, ReplayApplicator, ReplayCommitter, FileOwnership, FirstGenerationFlow, SkipApplicationFlow, NoPatchesFlow, NormalRegenerationFlow, ReplayService, FernignoreMigrator, REPLAY_FERNIGNORE_ENTRIES, GITATTRIBUTES_ENTRIES, EMPTY_RESULT;
|
|
23936
23949
|
var init_dist3 = __esm({
|
|
23937
|
-
"../../node_modules/.pnpm/@fern-api+replay@0.
|
|
23950
|
+
"../../node_modules/.pnpm/@fern-api+replay@0.16.0/node_modules/@fern-api/replay/dist/index.js"() {
|
|
23938
23951
|
"use strict";
|
|
23939
23952
|
init_esm4();
|
|
23940
23953
|
import_promises3 = require("fs/promises");
|
|
@@ -24414,8 +24427,48 @@ var init_dist3 = __esm({
|
|
|
24414
24427
|
this.lockManager = lockManager;
|
|
24415
24428
|
this.sdkOutputDir = sdkOutputDir;
|
|
24416
24429
|
}
|
|
24430
|
+
/**
|
|
24431
|
+
* Derive the previous-generation SHA from git history instead of trusting
|
|
24432
|
+
* `lock.current_generation`.
|
|
24433
|
+
*
|
|
24434
|
+
* Walks `git log HEAD --first-parent` and returns the SHA of the most recent
|
|
24435
|
+
* commit that `isGenerationBoundary` classifies as a customization-baseline
|
|
24436
|
+
* boundary, or null if no such commit is reachable from HEAD on the mainline.
|
|
24437
|
+
*
|
|
24438
|
+
* `isGenerationBoundary` is intentionally narrower than `isGenerationCommit`:
|
|
24439
|
+
* it excludes `[fern-autoversion]` (lightweight bumps that don't reset the
|
|
24440
|
+
* baseline) and the GitHub merge-commit subject for fern-bot regen PRs
|
|
24441
|
+
* (which sits on first-parent but where the customer fix-up commits live
|
|
24442
|
+
* on second-parent — stopping at the merge would hide them).
|
|
24443
|
+
*
|
|
24444
|
+
* See docs/adr/0001-derived-scan-boundary.md.
|
|
24445
|
+
*/
|
|
24446
|
+
async findPreviousGenerationFromHistory() {
|
|
24447
|
+
let log;
|
|
24448
|
+
try {
|
|
24449
|
+
log = await this.git.exec([
|
|
24450
|
+
"log",
|
|
24451
|
+
"--first-parent",
|
|
24452
|
+
"--format=%H%x00%an%x00%ae%x00%s",
|
|
24453
|
+
"HEAD"
|
|
24454
|
+
]);
|
|
24455
|
+
} catch {
|
|
24456
|
+
return null;
|
|
24457
|
+
}
|
|
24458
|
+
for (const commit of this.parseGitLog(log)) {
|
|
24459
|
+
if (isGenerationBoundary(commit)) {
|
|
24460
|
+
return commit.sha;
|
|
24461
|
+
}
|
|
24462
|
+
}
|
|
24463
|
+
return null;
|
|
24464
|
+
}
|
|
24417
24465
|
async detectNewPatches() {
|
|
24418
24466
|
const lock = this.lockManager.read();
|
|
24467
|
+
const derivedSha = await this.findPreviousGenerationFromHistory();
|
|
24468
|
+
if (derivedSha !== null) {
|
|
24469
|
+
const derivedRecord = await this.synthesizeGenerationRecord(derivedSha);
|
|
24470
|
+
return this.detectPatchesInRange(derivedSha, derivedRecord, lock);
|
|
24471
|
+
}
|
|
24419
24472
|
const lastGen = this.getLastGeneration(lock);
|
|
24420
24473
|
if (!lastGen) {
|
|
24421
24474
|
return { patches: [], revertedPatchIds: [] };
|
|
@@ -24423,7 +24476,7 @@ var init_dist3 = __esm({
|
|
|
24423
24476
|
const exists2 = await this.git.commitExists(lastGen.commit_sha);
|
|
24424
24477
|
if (!exists2) {
|
|
24425
24478
|
this.warnings.push(
|
|
24426
|
-
`Generation commit ${lastGen.commit_sha.slice(0, 7)} not found in git history. Falling back to
|
|
24479
|
+
`Generation commit ${lastGen.commit_sha.slice(0, 7)} not found in git history. Falling back to tree-diff detection (likely a shallow clone).`
|
|
24427
24480
|
);
|
|
24428
24481
|
return this.detectPatchesViaTreeDiff(
|
|
24429
24482
|
lastGen,
|
|
@@ -24431,44 +24484,8 @@ var init_dist3 = __esm({
|
|
|
24431
24484
|
true
|
|
24432
24485
|
);
|
|
24433
24486
|
}
|
|
24434
|
-
const isAncestor = await this.git.isAncestor(lastGen.commit_sha, "HEAD");
|
|
24435
|
-
if (!isAncestor) {
|
|
24436
|
-
return this.detectPatchesViaMergeBase(lastGen, lock);
|
|
24437
|
-
}
|
|
24438
24487
|
return this.detectPatchesInRange(lastGen.commit_sha, lastGen, lock);
|
|
24439
24488
|
}
|
|
24440
|
-
/**
|
|
24441
|
-
* Non-linear-history detection via `merge-base(prevGen, HEAD)`.
|
|
24442
|
-
*
|
|
24443
|
-
* After a squash-merge of a Fern-bot PR, `lastGen.commit_sha` (the previous
|
|
24444
|
-
* `[fern-generated]`) is orphaned but still in git's object database. The
|
|
24445
|
-
* merge-base is the commit on main from which the bot's branch was created —
|
|
24446
|
-
* a reachable ancestor of HEAD. Walking that range and classifying each
|
|
24447
|
-
* commit via `isGenerationCommit` mirrors the linear path and eliminates
|
|
24448
|
-
* the bug class where pipeline-driven changes (autoversion, replay,
|
|
24449
|
-
* generation) get bundled as customer customizations.
|
|
24450
|
-
*
|
|
24451
|
-
* Falls through to the legacy composite path when no common ancestor exists
|
|
24452
|
-
* (truly disjoint history — orphan branches with no shared root).
|
|
24453
|
-
*/
|
|
24454
|
-
async detectPatchesViaMergeBase(lastGen, lock) {
|
|
24455
|
-
let mergeBase = "";
|
|
24456
|
-
try {
|
|
24457
|
-
mergeBase = (await this.git.exec(["merge-base", lastGen.commit_sha, "HEAD"])).trim();
|
|
24458
|
-
} catch {
|
|
24459
|
-
}
|
|
24460
|
-
if (!mergeBase) {
|
|
24461
|
-
this.warnings.push(
|
|
24462
|
-
`No common ancestor between previous generation ${lastGen.commit_sha.slice(0, 7)} and HEAD. Falling back to composite tree-diff detection.`
|
|
24463
|
-
);
|
|
24464
|
-
return this.detectPatchesViaTreeDiff(
|
|
24465
|
-
lastGen,
|
|
24466
|
-
/* commitKnownMissing */
|
|
24467
|
-
false
|
|
24468
|
-
);
|
|
24469
|
-
}
|
|
24470
|
-
return this.detectPatchesInRange(mergeBase, lastGen, lock);
|
|
24471
|
-
}
|
|
24472
24489
|
/**
|
|
24473
24490
|
* Walk `${rangeStart}..HEAD`, classify each commit, emit one
|
|
24474
24491
|
* `StoredPatch` per customer commit. Body shared by the linear path
|
|
@@ -24904,6 +24921,26 @@ var init_dist3 = __esm({
|
|
|
24904
24921
|
getLastGeneration(lock) {
|
|
24905
24922
|
return lock.generations.find((g) => g.commit_sha === lock.current_generation);
|
|
24906
24923
|
}
|
|
24924
|
+
/**
|
|
24925
|
+
* Build a transient `GenerationRecord` from a SHA derived by walking git
|
|
24926
|
+
* history. Only `commit_sha` (and `tree_hash` when needed downstream) is
|
|
24927
|
+
* load-bearing here; the rest are filled with defensible placeholders.
|
|
24928
|
+
* This record is consumed by `detectPatchesInRange` and is never persisted.
|
|
24929
|
+
*/
|
|
24930
|
+
async synthesizeGenerationRecord(sha) {
|
|
24931
|
+
let tree_hash = "";
|
|
24932
|
+
try {
|
|
24933
|
+
tree_hash = await this.git.getTreeHash(sha);
|
|
24934
|
+
} catch {
|
|
24935
|
+
}
|
|
24936
|
+
return {
|
|
24937
|
+
commit_sha: sha,
|
|
24938
|
+
tree_hash,
|
|
24939
|
+
timestamp: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
24940
|
+
cli_version: "",
|
|
24941
|
+
generator_versions: {}
|
|
24942
|
+
};
|
|
24943
|
+
}
|
|
24907
24944
|
};
|
|
24908
24945
|
MergeAccumulator = class {
|
|
24909
24946
|
constructor(mode, sharedFiles) {
|
|
@@ -25526,8 +25563,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25526
25563
|
tree_hash: treeHash,
|
|
25527
25564
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25528
25565
|
cli_version: options?.cliVersion ?? "unknown",
|
|
25529
|
-
generator_versions: options?.generatorVersions ?? {}
|
|
25530
|
-
base_branch_head: options?.baseBranchHead
|
|
25566
|
+
generator_versions: options?.generatorVersions ?? {}
|
|
25531
25567
|
};
|
|
25532
25568
|
}
|
|
25533
25569
|
async stageAll() {
|
|
@@ -25598,7 +25634,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25598
25634
|
flow: "first-generation",
|
|
25599
25635
|
previousGenerationSha: null,
|
|
25600
25636
|
currentGenerationSha: headSha,
|
|
25601
|
-
baseBranchHead: options.baseBranchHead ?? null,
|
|
25602
25637
|
_prepared: {
|
|
25603
25638
|
kind: "terminal",
|
|
25604
25639
|
flow: "first-generation",
|
|
@@ -25608,8 +25643,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25608
25643
|
}
|
|
25609
25644
|
const commitOpts = options ? {
|
|
25610
25645
|
cliVersion: options.cliVersion ?? "unknown",
|
|
25611
|
-
generatorVersions: options.generatorVersions ?? {}
|
|
25612
|
-
baseBranchHead: options.baseBranchHead
|
|
25646
|
+
generatorVersions: options.generatorVersions ?? {}
|
|
25613
25647
|
} : void 0;
|
|
25614
25648
|
await this.service.committer.commitGeneration("Initial SDK generation", commitOpts);
|
|
25615
25649
|
const genRecord = await this.service.committer.createGenerationRecord(commitOpts);
|
|
@@ -25618,7 +25652,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25618
25652
|
flow: "first-generation",
|
|
25619
25653
|
previousGenerationSha: null,
|
|
25620
25654
|
currentGenerationSha: genRecord.commit_sha,
|
|
25621
|
-
baseBranchHead: options?.baseBranchHead ?? null,
|
|
25622
25655
|
_prepared: {
|
|
25623
25656
|
kind: "active",
|
|
25624
25657
|
flow: "first-generation",
|
|
@@ -25643,8 +25676,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25643
25676
|
async prepare(options) {
|
|
25644
25677
|
const commitOpts = options ? {
|
|
25645
25678
|
cliVersion: options.cliVersion ?? "unknown",
|
|
25646
|
-
generatorVersions: options.generatorVersions ?? {}
|
|
25647
|
-
baseBranchHead: options.baseBranchHead
|
|
25679
|
+
generatorVersions: options.generatorVersions ?? {}
|
|
25648
25680
|
} : void 0;
|
|
25649
25681
|
await this.service.committer.commitGeneration("Update SDK (replay skipped)", commitOpts);
|
|
25650
25682
|
await this.service.cleanupStaleConflictMarkers();
|
|
@@ -25666,7 +25698,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25666
25698
|
flow: "skip-application",
|
|
25667
25699
|
previousGenerationSha,
|
|
25668
25700
|
currentGenerationSha: genRecord.commit_sha,
|
|
25669
|
-
baseBranchHead: options?.baseBranchHead ?? null,
|
|
25670
25701
|
_prepared: {
|
|
25671
25702
|
kind: "active",
|
|
25672
25703
|
flow: "skip-application",
|
|
@@ -25725,7 +25756,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25725
25756
|
flow: "no-patches",
|
|
25726
25757
|
previousGenerationSha,
|
|
25727
25758
|
currentGenerationSha: headSha,
|
|
25728
|
-
baseBranchHead: options.baseBranchHead ?? null,
|
|
25729
25759
|
_prepared: {
|
|
25730
25760
|
kind: "terminal",
|
|
25731
25761
|
flow: "no-patches",
|
|
@@ -25757,8 +25787,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25757
25787
|
}
|
|
25758
25788
|
const commitOpts = options ? {
|
|
25759
25789
|
cliVersion: options.cliVersion ?? "unknown",
|
|
25760
|
-
generatorVersions: options.generatorVersions ?? {}
|
|
25761
|
-
baseBranchHead: options.baseBranchHead
|
|
25790
|
+
generatorVersions: options.generatorVersions ?? {}
|
|
25762
25791
|
} : void 0;
|
|
25763
25792
|
await this.service.committer.commitGeneration("Update SDK", commitOpts);
|
|
25764
25793
|
await this.service.cleanupStaleConflictMarkers();
|
|
@@ -25768,7 +25797,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25768
25797
|
flow: "no-patches",
|
|
25769
25798
|
previousGenerationSha,
|
|
25770
25799
|
currentGenerationSha: genRecord.commit_sha,
|
|
25771
|
-
baseBranchHead: options?.baseBranchHead ?? null,
|
|
25772
25800
|
_prepared: {
|
|
25773
25801
|
kind: "active",
|
|
25774
25802
|
flow: "no-patches",
|
|
@@ -25856,7 +25884,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25856
25884
|
flow: "normal-regeneration",
|
|
25857
25885
|
previousGenerationSha,
|
|
25858
25886
|
currentGenerationSha: headSha,
|
|
25859
|
-
baseBranchHead: options.baseBranchHead ?? null,
|
|
25860
25887
|
_prepared: {
|
|
25861
25888
|
kind: "terminal",
|
|
25862
25889
|
flow: "normal-regeneration",
|
|
@@ -25874,14 +25901,16 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25874
25901
|
existingPatches = this.service.lockManager.getPatches();
|
|
25875
25902
|
const seenHashes = /* @__PURE__ */ new Map();
|
|
25876
25903
|
for (const p2 of existingPatches) {
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25904
|
+
if (!p2.original_commit || p2.original_commit === "") {
|
|
25905
|
+
const priorPatchId = seenHashes.get(p2.content_hash);
|
|
25906
|
+
if (priorPatchId !== void 0) {
|
|
25907
|
+
this.service.lockManager.removePatch(p2.id);
|
|
25908
|
+
this.service.warnings.push(
|
|
25909
|
+
`Consolidated patch ${p2.id} into prior patch ${priorPatchId}: byte-identical patch_content. Lockfile collapsed to avoid duplicate-apply corruption on next regen.`
|
|
25910
|
+
);
|
|
25911
|
+
} else {
|
|
25912
|
+
seenHashes.set(p2.content_hash, p2.id);
|
|
25913
|
+
}
|
|
25885
25914
|
}
|
|
25886
25915
|
}
|
|
25887
25916
|
existingPatches = this.service.lockManager.getPatches();
|
|
@@ -25910,8 +25939,7 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25910
25939
|
const allPatches = [...existingPatches, ...newPatches];
|
|
25911
25940
|
const commitOpts = options ? {
|
|
25912
25941
|
cliVersion: options.cliVersion ?? "unknown",
|
|
25913
|
-
generatorVersions: options.generatorVersions ?? {}
|
|
25914
|
-
baseBranchHead: options.baseBranchHead
|
|
25942
|
+
generatorVersions: options.generatorVersions ?? {}
|
|
25915
25943
|
} : void 0;
|
|
25916
25944
|
await this.service.committer.commitGeneration("Update SDK", commitOpts);
|
|
25917
25945
|
await this.service.cleanupStaleConflictMarkers();
|
|
@@ -25921,7 +25949,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
25921
25949
|
flow: "normal-regeneration",
|
|
25922
25950
|
previousGenerationSha,
|
|
25923
25951
|
currentGenerationSha: genRecord.commit_sha,
|
|
25924
|
-
baseBranchHead: options?.baseBranchHead ?? null,
|
|
25925
25952
|
_prepared: {
|
|
25926
25953
|
kind: "active",
|
|
25927
25954
|
flow: "normal-regeneration",
|
|
@@ -26105,68 +26132,6 @@ Patches absorbed by generator (${buckets.absorbed.length}):`;
|
|
|
26105
26132
|
const prep = await this.prepareReplay(options);
|
|
26106
26133
|
return this.applyPreparedReplay(prep, options);
|
|
26107
26134
|
}
|
|
26108
|
-
/**
|
|
26109
|
-
* Sync the lockfile after a divergent PR was squash-merged.
|
|
26110
|
-
* Call this BEFORE runReplay() when the CLI detects a merged divergent PR.
|
|
26111
|
-
*
|
|
26112
|
-
* After updating the generation record, re-detects customer patches via
|
|
26113
|
-
* tree diff between the generation tag (pure generation tree) and HEAD
|
|
26114
|
-
* (which includes customer customizations after squash merge). This ensures
|
|
26115
|
-
* patches survive the squash merge → regenerate cycle even when the lockfile
|
|
26116
|
-
* was restored from the base branch during conflict PR creation.
|
|
26117
|
-
*/
|
|
26118
|
-
async syncFromDivergentMerge(generationCommitSha, options) {
|
|
26119
|
-
const treeHash = await this.git.getTreeHash(generationCommitSha);
|
|
26120
|
-
const timestamp = (await this.git.exec(["log", "-1", "--format=%aI", generationCommitSha])).trim();
|
|
26121
|
-
const record2 = {
|
|
26122
|
-
commit_sha: generationCommitSha,
|
|
26123
|
-
tree_hash: treeHash,
|
|
26124
|
-
timestamp,
|
|
26125
|
-
cli_version: options?.cliVersion ?? "unknown",
|
|
26126
|
-
generator_versions: options?.generatorVersions ?? {},
|
|
26127
|
-
base_branch_head: options?.baseBranchHead
|
|
26128
|
-
};
|
|
26129
|
-
let resolvedPatches;
|
|
26130
|
-
if (!this.lockManager.exists()) {
|
|
26131
|
-
this.lockManager.initializeInMemory(record2);
|
|
26132
|
-
} else {
|
|
26133
|
-
this.lockManager.read();
|
|
26134
|
-
const unresolvedPatches = [
|
|
26135
|
-
...this.lockManager.getUnresolvedPatches(),
|
|
26136
|
-
...this.lockManager.getResolvingPatches()
|
|
26137
|
-
];
|
|
26138
|
-
resolvedPatches = this.lockManager.getPatches().filter((p2) => p2.status == null);
|
|
26139
|
-
this.lockManager.addGeneration(record2);
|
|
26140
|
-
this.lockManager.clearPatches();
|
|
26141
|
-
for (const patch of unresolvedPatches) {
|
|
26142
|
-
this.lockManager.addPatch(patch);
|
|
26143
|
-
}
|
|
26144
|
-
}
|
|
26145
|
-
try {
|
|
26146
|
-
const { patches: redetectedPatches } = await this.detector.detectNewPatches();
|
|
26147
|
-
if (redetectedPatches.length > 0) {
|
|
26148
|
-
const redetectedFiles = new Set(redetectedPatches.flatMap((p2) => p2.files));
|
|
26149
|
-
const currentPatches = this.lockManager.getPatches();
|
|
26150
|
-
for (const patch of currentPatches) {
|
|
26151
|
-
if (patch.status != null && patch.files.some((f) => redetectedFiles.has(f))) {
|
|
26152
|
-
this.lockManager.removePatch(patch.id);
|
|
26153
|
-
}
|
|
26154
|
-
}
|
|
26155
|
-
for (const patch of redetectedPatches) {
|
|
26156
|
-
this.lockManager.addPatch(patch);
|
|
26157
|
-
}
|
|
26158
|
-
}
|
|
26159
|
-
} catch (error) {
|
|
26160
|
-
for (const patch of resolvedPatches ?? []) {
|
|
26161
|
-
this.lockManager.addPatch(patch);
|
|
26162
|
-
}
|
|
26163
|
-
this.detector.warnings.push(
|
|
26164
|
-
`Patch re-detection failed after divergent merge sync. ${(resolvedPatches ?? []).length} previously resolved patch(es) preserved. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
26165
|
-
);
|
|
26166
|
-
}
|
|
26167
|
-
this.lockManager.save();
|
|
26168
|
-
this.detector.warnings.push(...this.lockManager.warnings);
|
|
26169
|
-
}
|
|
26170
26135
|
determineFlow() {
|
|
26171
26136
|
try {
|
|
26172
26137
|
const lock = this.lockManager.read();
|
|
@@ -39645,19 +39610,10 @@ init_dist3();
|
|
|
39645
39610
|
|
|
39646
39611
|
// src/replay/replay-run.ts
|
|
39647
39612
|
init_dist3();
|
|
39648
|
-
var import_child_process4 = require("child_process");
|
|
39649
39613
|
var import_fs12 = require("fs");
|
|
39650
39614
|
var import_path20 = require("path");
|
|
39651
39615
|
async function replayPrepare(params, state) {
|
|
39652
|
-
const {
|
|
39653
|
-
outputDir,
|
|
39654
|
-
cliVersion,
|
|
39655
|
-
generatorVersions,
|
|
39656
|
-
stageOnly = false,
|
|
39657
|
-
generatorName,
|
|
39658
|
-
skipApplication,
|
|
39659
|
-
logger
|
|
39660
|
-
} = params;
|
|
39616
|
+
const { outputDir, cliVersion, generatorVersions, stageOnly = false, skipApplication, logger } = params;
|
|
39661
39617
|
const lockfilePath = (0, import_path20.join)(outputDir, ".fern", "replay.lock");
|
|
39662
39618
|
let autoBootstrapped = false;
|
|
39663
39619
|
let bootstrapAttempted = false;
|
|
@@ -39690,63 +39646,6 @@ async function replayPrepare(params, state) {
|
|
|
39690
39646
|
return null;
|
|
39691
39647
|
}
|
|
39692
39648
|
}
|
|
39693
|
-
const baseBranchHead = gitRevParse(outputDir, "HEAD");
|
|
39694
|
-
let previousGenerationSha = null;
|
|
39695
|
-
let prevBaseBranchHead = null;
|
|
39696
|
-
try {
|
|
39697
|
-
const lockManager = new LockfileManager(outputDir);
|
|
39698
|
-
if (lockManager.exists()) {
|
|
39699
|
-
const lock = lockManager.read();
|
|
39700
|
-
previousGenerationSha = lock.current_generation;
|
|
39701
|
-
const latestGen = lock.generations.find((g) => g.commit_sha === lock.current_generation);
|
|
39702
|
-
prevBaseBranchHead = latestGen?.base_branch_head ?? null;
|
|
39703
|
-
}
|
|
39704
|
-
} catch {
|
|
39705
|
-
}
|
|
39706
|
-
if (previousGenerationSha != null) {
|
|
39707
|
-
const sanitizedName = generatorName?.replace(/\//g, "--");
|
|
39708
|
-
const namespacedTag = sanitizedName != null ? `fern-generation-base--${sanitizedName}` : null;
|
|
39709
|
-
const tagSha = (namespacedTag != null ? gitRevParse(outputDir, namespacedTag) : null) ?? gitRevParse(outputDir, "fern-generation-base");
|
|
39710
|
-
let shouldSync = false;
|
|
39711
|
-
if (tagSha != null) {
|
|
39712
|
-
const tagParent = gitRevParse(outputDir, `${tagSha}^`);
|
|
39713
|
-
if (tagParent === prevBaseBranchHead || tagParent === previousGenerationSha) {
|
|
39714
|
-
const tagDistance = gitDiffNameOnly(outputDir, tagSha, "HEAD").length;
|
|
39715
|
-
const lockDistance = gitDiffNameOnly(
|
|
39716
|
-
outputDir,
|
|
39717
|
-
prevBaseBranchHead ?? previousGenerationSha,
|
|
39718
|
-
"HEAD"
|
|
39719
|
-
).length;
|
|
39720
|
-
shouldSync = tagDistance < lockDistance;
|
|
39721
|
-
}
|
|
39722
|
-
}
|
|
39723
|
-
if (shouldSync && tagSha != null) {
|
|
39724
|
-
if (!isTagMergedIntoHead(outputDir, tagSha)) {
|
|
39725
|
-
logger?.warn(
|
|
39726
|
-
`fern-generation-base tag ${tagSha} is not reachable from HEAD \u2014 skipping divergent-merge sync. The tag likely points at an unmerged generation (PR closed without merge).`
|
|
39727
|
-
);
|
|
39728
|
-
} else {
|
|
39729
|
-
try {
|
|
39730
|
-
const syncService = new ReplayService(outputDir, { enabled: true });
|
|
39731
|
-
await syncService.syncFromDivergentMerge(tagSha, {
|
|
39732
|
-
cliVersion,
|
|
39733
|
-
generatorVersions,
|
|
39734
|
-
baseBranchHead: baseBranchHead ?? void 0
|
|
39735
|
-
});
|
|
39736
|
-
} catch (error) {
|
|
39737
|
-
logger?.warn("Replay divergent-merge sync failed, continuing without sync: " + String(error));
|
|
39738
|
-
throw new ReplayPrepareError(String(error), error);
|
|
39739
|
-
}
|
|
39740
|
-
try {
|
|
39741
|
-
const freshLockManager = new LockfileManager(outputDir);
|
|
39742
|
-
if (freshLockManager.exists()) {
|
|
39743
|
-
previousGenerationSha = freshLockManager.read().current_generation;
|
|
39744
|
-
}
|
|
39745
|
-
} catch {
|
|
39746
|
-
}
|
|
39747
|
-
}
|
|
39748
|
-
}
|
|
39749
|
-
}
|
|
39750
39649
|
const service = new ReplayService(outputDir, { enabled: true });
|
|
39751
39650
|
let preparation;
|
|
39752
39651
|
try {
|
|
@@ -39754,8 +39653,7 @@ async function replayPrepare(params, state) {
|
|
|
39754
39653
|
cliVersion,
|
|
39755
39654
|
generatorVersions,
|
|
39756
39655
|
stageOnly,
|
|
39757
|
-
skipApplication
|
|
39758
|
-
baseBranchHead: baseBranchHead ?? void 0
|
|
39656
|
+
skipApplication
|
|
39759
39657
|
});
|
|
39760
39658
|
} catch (error) {
|
|
39761
39659
|
logger?.warn("Replay prepare failed, continuing without replay: " + String(error));
|
|
@@ -39766,9 +39664,8 @@ async function replayPrepare(params, state) {
|
|
|
39766
39664
|
_preparation: preparation,
|
|
39767
39665
|
outputDir,
|
|
39768
39666
|
flow: preparation.flow,
|
|
39769
|
-
previousGenerationSha,
|
|
39667
|
+
previousGenerationSha: preparation.previousGenerationSha,
|
|
39770
39668
|
currentGenerationSha: preparation.currentGenerationSha,
|
|
39771
|
-
baseBranchHead,
|
|
39772
39669
|
autoBootstrapped,
|
|
39773
39670
|
bootstrapAttempted
|
|
39774
39671
|
};
|
|
@@ -39785,24 +39682,11 @@ async function replayApply(prepared, params = {}) {
|
|
|
39785
39682
|
fernignoreUpdated: false,
|
|
39786
39683
|
previousGenerationSha: prepared.previousGenerationSha,
|
|
39787
39684
|
currentGenerationSha: prepared.currentGenerationSha,
|
|
39788
|
-
baseBranchHead: prepared.baseBranchHead,
|
|
39789
39685
|
autoBootstrapped: prepared.autoBootstrapped,
|
|
39790
39686
|
bootstrapAttempted: prepared.bootstrapAttempted,
|
|
39791
39687
|
failureReason: String(error)
|
|
39792
39688
|
};
|
|
39793
39689
|
}
|
|
39794
|
-
let resolvedBaseBranchHead = prepared.baseBranchHead;
|
|
39795
|
-
try {
|
|
39796
|
-
const freshLockManager = new LockfileManager(prepared.outputDir);
|
|
39797
|
-
if (freshLockManager.exists()) {
|
|
39798
|
-
const freshLock = freshLockManager.read();
|
|
39799
|
-
const latestGen = freshLock.generations.find((g) => g.commit_sha === freshLock.current_generation);
|
|
39800
|
-
if (latestGen?.base_branch_head) {
|
|
39801
|
-
resolvedBaseBranchHead = latestGen.base_branch_head;
|
|
39802
|
-
}
|
|
39803
|
-
}
|
|
39804
|
-
} catch {
|
|
39805
|
-
}
|
|
39806
39690
|
const fernignoreUpdated = await ensureReplayFernignoreEntries(prepared.outputDir);
|
|
39807
39691
|
await ensureGitattributesEntries2(prepared.outputDir);
|
|
39808
39692
|
return {
|
|
@@ -39810,7 +39694,6 @@ async function replayApply(prepared, params = {}) {
|
|
|
39810
39694
|
fernignoreUpdated,
|
|
39811
39695
|
previousGenerationSha: prepared.previousGenerationSha,
|
|
39812
39696
|
currentGenerationSha: prepared.currentGenerationSha,
|
|
39813
|
-
baseBranchHead: resolvedBaseBranchHead,
|
|
39814
39697
|
autoBootstrapped: prepared.autoBootstrapped,
|
|
39815
39698
|
bootstrapAttempted: prepared.bootstrapAttempted
|
|
39816
39699
|
};
|
|
@@ -39826,7 +39709,6 @@ async function replayRun(params) {
|
|
|
39826
39709
|
fernignoreUpdated: false,
|
|
39827
39710
|
previousGenerationSha: null,
|
|
39828
39711
|
currentGenerationSha: null,
|
|
39829
|
-
baseBranchHead: null,
|
|
39830
39712
|
autoBootstrapped: false,
|
|
39831
39713
|
bootstrapAttempted: prepareState.bootstrapAttempted,
|
|
39832
39714
|
failureReason: error instanceof ReplayPrepareError ? error.reason : String(error)
|
|
@@ -39838,7 +39720,6 @@ async function replayRun(params) {
|
|
|
39838
39720
|
fernignoreUpdated: false,
|
|
39839
39721
|
previousGenerationSha: null,
|
|
39840
39722
|
currentGenerationSha: null,
|
|
39841
|
-
baseBranchHead: null,
|
|
39842
39723
|
autoBootstrapped: false,
|
|
39843
39724
|
bootstrapAttempted: prepareState.bootstrapAttempted
|
|
39844
39725
|
};
|
|
@@ -39857,53 +39738,6 @@ var ReplayPrepareError = class extends Error {
|
|
|
39857
39738
|
this.reason = reason;
|
|
39858
39739
|
}
|
|
39859
39740
|
};
|
|
39860
|
-
function isTagMergedIntoHead(cwd2, tagSha) {
|
|
39861
|
-
try {
|
|
39862
|
-
(0, import_child_process4.execFileSync)("git", ["merge-base", "--is-ancestor", tagSha, "HEAD"], {
|
|
39863
|
-
cwd: cwd2,
|
|
39864
|
-
stdio: "pipe"
|
|
39865
|
-
});
|
|
39866
|
-
return true;
|
|
39867
|
-
} catch {
|
|
39868
|
-
}
|
|
39869
|
-
const tagTree = gitRevParse(cwd2, `${tagSha}^{tree}`);
|
|
39870
|
-
if (tagTree == null) {
|
|
39871
|
-
return false;
|
|
39872
|
-
}
|
|
39873
|
-
try {
|
|
39874
|
-
const trees = (0, import_child_process4.execFileSync)("git", ["log", "HEAD", "--format=%T", "--max-count=500"], {
|
|
39875
|
-
cwd: cwd2,
|
|
39876
|
-
encoding: "utf-8",
|
|
39877
|
-
stdio: "pipe"
|
|
39878
|
-
});
|
|
39879
|
-
return trees.split("\n").some((t2) => t2.trim() === tagTree);
|
|
39880
|
-
} catch {
|
|
39881
|
-
return false;
|
|
39882
|
-
}
|
|
39883
|
-
}
|
|
39884
|
-
function gitRevParse(cwd2, rev) {
|
|
39885
|
-
try {
|
|
39886
|
-
return (0, import_child_process4.execFileSync)("git", ["rev-parse", "--verify", rev], {
|
|
39887
|
-
cwd: cwd2,
|
|
39888
|
-
encoding: "utf-8",
|
|
39889
|
-
stdio: "pipe"
|
|
39890
|
-
}).trim();
|
|
39891
|
-
} catch {
|
|
39892
|
-
return null;
|
|
39893
|
-
}
|
|
39894
|
-
}
|
|
39895
|
-
function gitDiffNameOnly(cwd2, from, to) {
|
|
39896
|
-
try {
|
|
39897
|
-
const output = (0, import_child_process4.execFileSync)("git", ["diff", "--name-only", from, to], {
|
|
39898
|
-
cwd: cwd2,
|
|
39899
|
-
encoding: "utf-8",
|
|
39900
|
-
stdio: "pipe"
|
|
39901
|
-
});
|
|
39902
|
-
return output.trim().split("\n").filter(Boolean);
|
|
39903
|
-
} catch {
|
|
39904
|
-
return [];
|
|
39905
|
-
}
|
|
39906
|
-
}
|
|
39907
39741
|
|
|
39908
39742
|
// src/replay/replay-status.ts
|
|
39909
39743
|
init_dist3();
|
|
@@ -39951,7 +39785,7 @@ var consolePipelineLogger = {
|
|
|
39951
39785
|
};
|
|
39952
39786
|
|
|
39953
39787
|
// src/pipeline/PostGenerationPipeline.ts
|
|
39954
|
-
var
|
|
39788
|
+
var import_child_process6 = require("child_process");
|
|
39955
39789
|
|
|
39956
39790
|
// src/pipeline/github/constants.ts
|
|
39957
39791
|
var FERN_BOT_NAME2 = "fern-api";
|
|
@@ -39959,7 +39793,7 @@ var FERN_BOT_EMAIL2 = "115122769+fern-api[bot]@users.noreply.github.com";
|
|
|
39959
39793
|
var FERN_BOT_LOGIN2 = "fern-api[bot]";
|
|
39960
39794
|
|
|
39961
39795
|
// src/pipeline/steps/AutoVersionStep.ts
|
|
39962
|
-
var
|
|
39796
|
+
var import_child_process4 = require("child_process");
|
|
39963
39797
|
var import_fs14 = require("fs");
|
|
39964
39798
|
var import_promises15 = require("fs/promises");
|
|
39965
39799
|
var import_path22 = require("path");
|
|
@@ -41333,7 +41167,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41333
41167
|
}
|
|
41334
41168
|
async readVersionFromMetadata() {
|
|
41335
41169
|
try {
|
|
41336
|
-
const output = (0,
|
|
41170
|
+
const output = (0, import_child_process4.execFileSync)("git", ["show", "HEAD~1:.fern/metadata.json"], {
|
|
41337
41171
|
cwd: this.outputDir,
|
|
41338
41172
|
encoding: "utf-8",
|
|
41339
41173
|
stdio: "pipe"
|
|
@@ -41349,7 +41183,7 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41349
41183
|
return mappedMagicVersion.startsWith("v") ? `v${stripped}` : stripped;
|
|
41350
41184
|
}
|
|
41351
41185
|
gitDiff(from, to) {
|
|
41352
|
-
return (0,
|
|
41186
|
+
return (0, import_child_process4.execFileSync)("git", ["diff", from, to, "--", ".", ":(exclude).fern/metadata.json"], {
|
|
41353
41187
|
cwd: this.outputDir,
|
|
41354
41188
|
encoding: "utf-8",
|
|
41355
41189
|
stdio: "pipe",
|
|
@@ -41362,12 +41196,12 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41362
41196
|
const fullMessage = body.length > 0 ? `${COMMIT_MARKER} ${subject}
|
|
41363
41197
|
|
|
41364
41198
|
${body}` : `${COMMIT_MARKER} ${subject}`;
|
|
41365
|
-
(0,
|
|
41366
|
-
(0,
|
|
41199
|
+
(0, import_child_process4.execFileSync)("git", ["add", "-A"], { cwd: this.outputDir, stdio: "pipe" });
|
|
41200
|
+
(0, import_child_process4.execFileSync)("git", ["commit", "--allow-empty", "-m", fullMessage], {
|
|
41367
41201
|
cwd: this.outputDir,
|
|
41368
41202
|
stdio: "pipe"
|
|
41369
41203
|
});
|
|
41370
|
-
return (0,
|
|
41204
|
+
return (0, import_child_process4.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
41371
41205
|
cwd: this.outputDir,
|
|
41372
41206
|
encoding: "utf-8",
|
|
41373
41207
|
stdio: "pipe"
|
|
@@ -41542,19 +41376,17 @@ ${newBlock}${remainder}`;
|
|
|
41542
41376
|
};
|
|
41543
41377
|
|
|
41544
41378
|
// src/pipeline/steps/GenerationCommitStep.ts
|
|
41545
|
-
var
|
|
41379
|
+
var import_child_process5 = require("child_process");
|
|
41546
41380
|
var GenerationCommitStep = class extends BaseStep {
|
|
41547
|
-
constructor(outputDir, logger, config, cliVersion, generatorVersions
|
|
41381
|
+
constructor(outputDir, logger, config, cliVersion, generatorVersions) {
|
|
41548
41382
|
super(outputDir, logger);
|
|
41549
41383
|
this.config = config;
|
|
41550
41384
|
this.cliVersion = cliVersion;
|
|
41551
41385
|
this.generatorVersions = generatorVersions;
|
|
41552
|
-
this.generatorName = generatorName;
|
|
41553
41386
|
}
|
|
41554
41387
|
config;
|
|
41555
41388
|
cliVersion;
|
|
41556
41389
|
generatorVersions;
|
|
41557
|
-
generatorName;
|
|
41558
41390
|
name = "generationCommit";
|
|
41559
41391
|
async execute(_context) {
|
|
41560
41392
|
const headBeforePrepare = tryRevParse(this.outputDir, "HEAD");
|
|
@@ -41566,7 +41398,6 @@ var GenerationCommitStep = class extends BaseStep {
|
|
|
41566
41398
|
outputDir: this.outputDir,
|
|
41567
41399
|
cliVersion: this.cliVersion,
|
|
41568
41400
|
generatorVersions: this.generatorVersions,
|
|
41569
|
-
generatorName: this.generatorName,
|
|
41570
41401
|
skipApplication: this.config.skipApplication,
|
|
41571
41402
|
logger: this.logger
|
|
41572
41403
|
},
|
|
@@ -41576,7 +41407,7 @@ var GenerationCommitStep = class extends BaseStep {
|
|
|
41576
41407
|
const reason = error instanceof ReplayPrepareError ? error.reason : String(error);
|
|
41577
41408
|
if (headBeforePrepare != null) {
|
|
41578
41409
|
try {
|
|
41579
|
-
(0,
|
|
41410
|
+
(0, import_child_process5.execFileSync)("git", ["reset", "--hard", headBeforePrepare], {
|
|
41580
41411
|
cwd: this.outputDir,
|
|
41581
41412
|
stdio: "pipe"
|
|
41582
41413
|
});
|
|
@@ -41605,7 +41436,6 @@ var GenerationCommitStep = class extends BaseStep {
|
|
|
41605
41436
|
preparedReplay: prepared,
|
|
41606
41437
|
previousGenerationSha: prepared.previousGenerationSha ?? void 0,
|
|
41607
41438
|
currentGenerationSha: prepared.currentGenerationSha,
|
|
41608
|
-
baseBranchHead: prepared.baseBranchHead ?? void 0,
|
|
41609
41439
|
flow: prepared.flow,
|
|
41610
41440
|
bootstrapAttempted: prepareState.bootstrapAttempted
|
|
41611
41441
|
};
|
|
@@ -41613,7 +41443,7 @@ var GenerationCommitStep = class extends BaseStep {
|
|
|
41613
41443
|
};
|
|
41614
41444
|
function tryRevParse(cwd2, rev) {
|
|
41615
41445
|
try {
|
|
41616
|
-
return (0,
|
|
41446
|
+
return (0, import_child_process5.execFileSync)("git", ["rev-parse", "--verify", rev], {
|
|
41617
41447
|
cwd: cwd2,
|
|
41618
41448
|
encoding: "utf-8",
|
|
41619
41449
|
stdio: "pipe"
|
|
@@ -41787,18 +41617,16 @@ async function pushSignedCommit({
|
|
|
41787
41617
|
await repository.pushObjectToRef(localHeadSha, tempRef);
|
|
41788
41618
|
tempRefPushed = true;
|
|
41789
41619
|
for (let attempt2 = 0; attempt2 < MAX_CONCURRENT_PUSH_RETRIES; attempt2++) {
|
|
41790
|
-
const
|
|
41791
|
-
|
|
41792
|
-
email: author?.email ?? FERN_BOT_EMAIL2
|
|
41793
|
-
};
|
|
41620
|
+
const resolvedAuthor = author ?? { name: FERN_BOT_NAME2, email: FERN_BOT_EMAIL2 };
|
|
41621
|
+
const committerField = author != null ? { committer: author } : {};
|
|
41794
41622
|
const { data: signedCommit } = await octokit.git.createCommit({
|
|
41795
41623
|
owner,
|
|
41796
41624
|
repo,
|
|
41797
41625
|
message,
|
|
41798
41626
|
tree: treeSha,
|
|
41799
41627
|
parents,
|
|
41800
|
-
author:
|
|
41801
|
-
|
|
41628
|
+
author: resolvedAuthor,
|
|
41629
|
+
...committerField
|
|
41802
41630
|
});
|
|
41803
41631
|
const signedSha = signedCommit.sha;
|
|
41804
41632
|
try {
|
|
@@ -42360,17 +42188,15 @@ function resolveBranchAction({
|
|
|
42360
42188
|
|
|
42361
42189
|
// src/pipeline/steps/ReplayStep.ts
|
|
42362
42190
|
var ReplayStep = class extends BaseStep {
|
|
42363
|
-
constructor(outputDir, logger, config, cliVersion, generatorVersions
|
|
42191
|
+
constructor(outputDir, logger, config, cliVersion, generatorVersions) {
|
|
42364
42192
|
super(outputDir, logger);
|
|
42365
42193
|
this.config = config;
|
|
42366
42194
|
this.cliVersion = cliVersion;
|
|
42367
42195
|
this.generatorVersions = generatorVersions;
|
|
42368
|
-
this.generatorName = generatorName;
|
|
42369
42196
|
}
|
|
42370
42197
|
config;
|
|
42371
42198
|
cliVersion;
|
|
42372
42199
|
generatorVersions;
|
|
42373
|
-
generatorName;
|
|
42374
42200
|
name = "replay";
|
|
42375
42201
|
async execute(context) {
|
|
42376
42202
|
const generationCommit = context.previousStepResults.generationCommit;
|
|
@@ -42409,7 +42235,6 @@ var ReplayStep = class extends BaseStep {
|
|
|
42409
42235
|
cliVersion: this.cliVersion,
|
|
42410
42236
|
generatorVersions: this.generatorVersions,
|
|
42411
42237
|
stageOnly: this.config.stageOnly ?? false,
|
|
42412
|
-
generatorName: this.generatorName,
|
|
42413
42238
|
skipApplication: this.config.skipApplication,
|
|
42414
42239
|
logger: this.logger
|
|
42415
42240
|
});
|
|
@@ -42421,7 +42246,6 @@ var ReplayStep = class extends BaseStep {
|
|
|
42421
42246
|
errorMessage: result.failureReason,
|
|
42422
42247
|
previousGenerationSha: result.previousGenerationSha ?? void 0,
|
|
42423
42248
|
currentGenerationSha: result.currentGenerationSha ?? void 0,
|
|
42424
|
-
baseBranchHead: result.baseBranchHead ?? void 0,
|
|
42425
42249
|
autoBootstrapped: result.autoBootstrapped,
|
|
42426
42250
|
bootstrapAttempted: result.bootstrapAttempted,
|
|
42427
42251
|
flow: "normal-regeneration",
|
|
@@ -42436,7 +42260,6 @@ var ReplayStep = class extends BaseStep {
|
|
|
42436
42260
|
success: true,
|
|
42437
42261
|
previousGenerationSha: result.previousGenerationSha ?? void 0,
|
|
42438
42262
|
currentGenerationSha: result.currentGenerationSha ?? void 0,
|
|
42439
|
-
baseBranchHead: result.baseBranchHead ?? void 0,
|
|
42440
42263
|
autoBootstrapped: result.autoBootstrapped,
|
|
42441
42264
|
bootstrapAttempted: result.bootstrapAttempted,
|
|
42442
42265
|
flow: "first-generation",
|
|
@@ -42451,7 +42274,6 @@ var ReplayStep = class extends BaseStep {
|
|
|
42451
42274
|
success: true,
|
|
42452
42275
|
previousGenerationSha: result.previousGenerationSha ?? void 0,
|
|
42453
42276
|
currentGenerationSha: result.currentGenerationSha ?? void 0,
|
|
42454
|
-
baseBranchHead: result.baseBranchHead ?? void 0,
|
|
42455
42277
|
autoBootstrapped: result.autoBootstrapped,
|
|
42456
42278
|
bootstrapAttempted: result.bootstrapAttempted,
|
|
42457
42279
|
flow: report.flow,
|
|
@@ -42723,8 +42545,7 @@ var PostGenerationPipeline = class {
|
|
|
42723
42545
|
this.logger,
|
|
42724
42546
|
{ enabled: true, skipApplication: config.replay.skipApplication },
|
|
42725
42547
|
config.cliVersion,
|
|
42726
|
-
config.generatorVersions
|
|
42727
|
-
config.generatorName
|
|
42548
|
+
config.generatorVersions
|
|
42728
42549
|
)
|
|
42729
42550
|
);
|
|
42730
42551
|
}
|
|
@@ -42738,8 +42559,7 @@ var PostGenerationPipeline = class {
|
|
|
42738
42559
|
this.logger,
|
|
42739
42560
|
config.replay,
|
|
42740
42561
|
config.cliVersion,
|
|
42741
|
-
config.generatorVersions
|
|
42742
|
-
config.generatorName
|
|
42562
|
+
config.generatorVersions
|
|
42743
42563
|
)
|
|
42744
42564
|
);
|
|
42745
42565
|
}
|
|
@@ -42764,8 +42584,8 @@ var PostGenerationPipeline = class {
|
|
|
42764
42584
|
async run() {
|
|
42765
42585
|
if (this.config.github?.enabled) {
|
|
42766
42586
|
try {
|
|
42767
|
-
(0,
|
|
42768
|
-
(0,
|
|
42587
|
+
(0, import_child_process6.execFileSync)("git", ["config", "user.name", FERN_BOT_NAME2], { cwd: this.config.outputDir });
|
|
42588
|
+
(0, import_child_process6.execFileSync)("git", ["config", "user.email", FERN_BOT_EMAIL2], { cwd: this.config.outputDir });
|
|
42769
42589
|
} catch {
|
|
42770
42590
|
}
|
|
42771
42591
|
}
|
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.32",
|
|
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.16.0",
|
|
27
27
|
"@octokit/rest": "^22.0.1",
|
|
28
28
|
"es-toolkit": "^1.45.1",
|
|
29
29
|
"semver": "^7.6.3",
|