@fern-api/replay 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +170 -61
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +171 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -8
- package/dist/index.d.ts +19 -8
- package/dist/index.js +169 -61
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -5335,6 +5335,9 @@ var init_GitClient = __esm({
|
|
|
5335
5335
|
return false;
|
|
5336
5336
|
}
|
|
5337
5337
|
}
|
|
5338
|
+
async getCommitBody(commitSha) {
|
|
5339
|
+
return this.exec(["log", "-1", "--format=%B", commitSha]);
|
|
5340
|
+
}
|
|
5338
5341
|
getRepoPath() {
|
|
5339
5342
|
return this.repoPath;
|
|
5340
5343
|
}
|
|
@@ -13009,6 +13012,17 @@ function isGenerationCommit(commit) {
|
|
|
13009
13012
|
function isReplayCommit(commit) {
|
|
13010
13013
|
return commit.message.startsWith("[fern-replay]");
|
|
13011
13014
|
}
|
|
13015
|
+
function isRevertCommit(message) {
|
|
13016
|
+
return message.startsWith('Revert "');
|
|
13017
|
+
}
|
|
13018
|
+
function parseRevertedSha(fullBody) {
|
|
13019
|
+
const match2 = fullBody.match(/This reverts commit ([0-9a-f]{40})\./);
|
|
13020
|
+
return match2?.[1];
|
|
13021
|
+
}
|
|
13022
|
+
function parseRevertedMessage(subject) {
|
|
13023
|
+
const match2 = subject.match(/^Revert "(.+)"$/);
|
|
13024
|
+
return match2?.[1];
|
|
13025
|
+
}
|
|
13012
13026
|
|
|
13013
13027
|
// src/ReplayDetector.ts
|
|
13014
13028
|
var INFRASTRUCTURE_FILES = /* @__PURE__ */ new Set([".fernignore"]);
|
|
@@ -13026,14 +13040,14 @@ var ReplayDetector = class {
|
|
|
13026
13040
|
const lock = this.lockManager.read();
|
|
13027
13041
|
const lastGen = this.getLastGeneration(lock);
|
|
13028
13042
|
if (!lastGen) {
|
|
13029
|
-
return [];
|
|
13043
|
+
return { patches: [], revertedPatchIds: [] };
|
|
13030
13044
|
}
|
|
13031
13045
|
const exists2 = await this.git.commitExists(lastGen.commit_sha);
|
|
13032
13046
|
if (!exists2) {
|
|
13033
13047
|
this.warnings.push(
|
|
13034
13048
|
`Generation commit ${lastGen.commit_sha.slice(0, 7)} not found in git history. Skipping new patch detection. Existing lockfile patches will still be applied.`
|
|
13035
13049
|
);
|
|
13036
|
-
return [];
|
|
13050
|
+
return { patches: [], revertedPatchIds: [] };
|
|
13037
13051
|
}
|
|
13038
13052
|
const isAncestor = await this.git.isAncestor(lastGen.commit_sha, "HEAD");
|
|
13039
13053
|
if (!isAncestor) {
|
|
@@ -13047,7 +13061,7 @@ var ReplayDetector = class {
|
|
|
13047
13061
|
this.sdkOutputDir
|
|
13048
13062
|
]);
|
|
13049
13063
|
if (!log.trim()) {
|
|
13050
|
-
return [];
|
|
13064
|
+
return { patches: [], revertedPatchIds: [] };
|
|
13051
13065
|
}
|
|
13052
13066
|
const commits = this.parseGitLog(log);
|
|
13053
13067
|
const newPatches = [];
|
|
@@ -13083,7 +13097,60 @@ var ReplayDetector = class {
|
|
|
13083
13097
|
patch_content: patchContent
|
|
13084
13098
|
});
|
|
13085
13099
|
}
|
|
13086
|
-
|
|
13100
|
+
newPatches.reverse();
|
|
13101
|
+
const revertedPatchIdSet = /* @__PURE__ */ new Set();
|
|
13102
|
+
const revertIndicesToRemove = /* @__PURE__ */ new Set();
|
|
13103
|
+
for (let i = 0; i < newPatches.length; i++) {
|
|
13104
|
+
const patch = newPatches[i];
|
|
13105
|
+
if (!isRevertCommit(patch.original_message)) continue;
|
|
13106
|
+
let body = "";
|
|
13107
|
+
try {
|
|
13108
|
+
body = await this.git.getCommitBody(patch.original_commit);
|
|
13109
|
+
} catch {
|
|
13110
|
+
}
|
|
13111
|
+
const revertedSha = parseRevertedSha(body);
|
|
13112
|
+
const revertedMessage = parseRevertedMessage(patch.original_message);
|
|
13113
|
+
let matchedExisting = false;
|
|
13114
|
+
if (revertedSha) {
|
|
13115
|
+
const existing = lock.patches.find((p) => p.original_commit === revertedSha);
|
|
13116
|
+
if (existing) {
|
|
13117
|
+
revertedPatchIdSet.add(existing.id);
|
|
13118
|
+
revertIndicesToRemove.add(i);
|
|
13119
|
+
matchedExisting = true;
|
|
13120
|
+
}
|
|
13121
|
+
}
|
|
13122
|
+
if (!matchedExisting && revertedMessage) {
|
|
13123
|
+
const existing = lock.patches.find((p) => p.original_message === revertedMessage);
|
|
13124
|
+
if (existing) {
|
|
13125
|
+
revertedPatchIdSet.add(existing.id);
|
|
13126
|
+
revertIndicesToRemove.add(i);
|
|
13127
|
+
matchedExisting = true;
|
|
13128
|
+
}
|
|
13129
|
+
}
|
|
13130
|
+
if (matchedExisting) continue;
|
|
13131
|
+
let matchedNew = false;
|
|
13132
|
+
if (revertedSha) {
|
|
13133
|
+
const idx = newPatches.findIndex(
|
|
13134
|
+
(p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_commit === revertedSha
|
|
13135
|
+
);
|
|
13136
|
+
if (idx !== -1) {
|
|
13137
|
+
revertIndicesToRemove.add(i);
|
|
13138
|
+
revertIndicesToRemove.add(idx);
|
|
13139
|
+
matchedNew = true;
|
|
13140
|
+
}
|
|
13141
|
+
}
|
|
13142
|
+
if (!matchedNew && revertedMessage) {
|
|
13143
|
+
const idx = newPatches.findIndex(
|
|
13144
|
+
(p, j) => j !== i && !revertIndicesToRemove.has(j) && p.original_message === revertedMessage
|
|
13145
|
+
);
|
|
13146
|
+
if (idx !== -1) {
|
|
13147
|
+
revertIndicesToRemove.add(i);
|
|
13148
|
+
revertIndicesToRemove.add(idx);
|
|
13149
|
+
}
|
|
13150
|
+
}
|
|
13151
|
+
}
|
|
13152
|
+
const filteredPatches = newPatches.filter((_, i) => !revertIndicesToRemove.has(i));
|
|
13153
|
+
return { patches: filteredPatches, revertedPatchIds: [...revertedPatchIdSet] };
|
|
13087
13154
|
}
|
|
13088
13155
|
/**
|
|
13089
13156
|
* Compute content hash for deduplication.
|
|
@@ -13094,31 +13161,34 @@ var ReplayDetector = class {
|
|
|
13094
13161
|
const normalized = patchContent.split("\n").filter((line) => !line.startsWith("From ") && !line.startsWith("index ") && !line.startsWith("Date: ")).join("\n");
|
|
13095
13162
|
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(normalized).digest("hex")}`;
|
|
13096
13163
|
}
|
|
13097
|
-
/**
|
|
13164
|
+
/**
|
|
13165
|
+
* Detect patches via tree diff for non-linear history. Returns a composite patch.
|
|
13166
|
+
* Revert reconciliation is skipped here because tree-diff produces a single composite
|
|
13167
|
+
* patch from the aggregate diff — individual revert commits are not distinguishable.
|
|
13168
|
+
*/
|
|
13098
13169
|
async detectPatchesViaTreeDiff(lastGen) {
|
|
13099
13170
|
const filesOutput = await this.git.exec(["diff", "--name-only", lastGen.commit_sha, "HEAD"]);
|
|
13100
13171
|
const files = filesOutput.trim().split("\n").filter(Boolean).filter((f) => !INFRASTRUCTURE_FILES.has(f)).filter((f) => !f.startsWith(".fern/"));
|
|
13101
|
-
if (files.length === 0) return [];
|
|
13172
|
+
if (files.length === 0) return { patches: [], revertedPatchIds: [] };
|
|
13102
13173
|
const diff = await this.git.exec(["diff", lastGen.commit_sha, "HEAD", "--", ...files]);
|
|
13103
|
-
if (!diff.trim()) return [];
|
|
13174
|
+
if (!diff.trim()) return { patches: [], revertedPatchIds: [] };
|
|
13104
13175
|
const contentHash = this.computeContentHash(diff);
|
|
13105
13176
|
const lock = this.lockManager.read();
|
|
13106
13177
|
if (lock.patches.some((p) => p.content_hash === contentHash)) {
|
|
13107
|
-
return [];
|
|
13178
|
+
return { patches: [], revertedPatchIds: [] };
|
|
13108
13179
|
}
|
|
13109
13180
|
const headSha = (await this.git.exec(["rev-parse", "HEAD"])).trim();
|
|
13110
|
-
|
|
13111
|
-
{
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
];
|
|
13181
|
+
const compositePatch = {
|
|
13182
|
+
id: `patch-composite-${headSha.slice(0, 8)}`,
|
|
13183
|
+
content_hash: contentHash,
|
|
13184
|
+
original_commit: headSha,
|
|
13185
|
+
original_message: "Customer customizations (composite)",
|
|
13186
|
+
original_author: "composite",
|
|
13187
|
+
base_generation: lastGen.commit_sha,
|
|
13188
|
+
files,
|
|
13189
|
+
patch_content: diff
|
|
13190
|
+
};
|
|
13191
|
+
return { patches: [compositePatch], revertedPatchIds: [] };
|
|
13122
13192
|
}
|
|
13123
13193
|
parseGitLog(log) {
|
|
13124
13194
|
return log.trim().split("\n").map((line) => {
|
|
@@ -15266,6 +15336,34 @@ CLI Version: ${options.cliVersion}`;
|
|
|
15266
15336
|
}
|
|
15267
15337
|
};
|
|
15268
15338
|
|
|
15339
|
+
// src/conflict-utils.ts
|
|
15340
|
+
function stripConflictMarkers(content) {
|
|
15341
|
+
const lines = content.split("\n");
|
|
15342
|
+
const result = [];
|
|
15343
|
+
let inConflict = false;
|
|
15344
|
+
let inOurs = false;
|
|
15345
|
+
for (const line of lines) {
|
|
15346
|
+
if (line.startsWith("<<<<<<< ")) {
|
|
15347
|
+
inConflict = true;
|
|
15348
|
+
inOurs = true;
|
|
15349
|
+
continue;
|
|
15350
|
+
}
|
|
15351
|
+
if (inConflict && line === "=======") {
|
|
15352
|
+
inOurs = false;
|
|
15353
|
+
continue;
|
|
15354
|
+
}
|
|
15355
|
+
if (inConflict && line.startsWith(">>>>>>> ")) {
|
|
15356
|
+
inConflict = false;
|
|
15357
|
+
inOurs = false;
|
|
15358
|
+
continue;
|
|
15359
|
+
}
|
|
15360
|
+
if (!inConflict || inOurs) {
|
|
15361
|
+
result.push(line);
|
|
15362
|
+
}
|
|
15363
|
+
}
|
|
15364
|
+
return result.join("\n");
|
|
15365
|
+
}
|
|
15366
|
+
|
|
15269
15367
|
// src/ReplayService.ts
|
|
15270
15368
|
var ReplayService = class {
|
|
15271
15369
|
git;
|
|
@@ -15334,7 +15432,7 @@ var ReplayService = class {
|
|
|
15334
15432
|
}
|
|
15335
15433
|
this.lockManager.save();
|
|
15336
15434
|
try {
|
|
15337
|
-
const redetectedPatches = await this.detector.detectNewPatches();
|
|
15435
|
+
const { patches: redetectedPatches } = await this.detector.detectNewPatches();
|
|
15338
15436
|
if (redetectedPatches.length > 0) {
|
|
15339
15437
|
const redetectedFiles = new Set(redetectedPatches.flatMap((p) => p.files));
|
|
15340
15438
|
const currentPatches = this.lockManager.getPatches();
|
|
@@ -15425,7 +15523,7 @@ var ReplayService = class {
|
|
|
15425
15523
|
};
|
|
15426
15524
|
}
|
|
15427
15525
|
async handleNoPatchesRegeneration(options) {
|
|
15428
|
-
const newPatches = await this.detector.detectNewPatches();
|
|
15526
|
+
const { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();
|
|
15429
15527
|
const warnings = [...this.detector.warnings];
|
|
15430
15528
|
if (options?.dryRun) {
|
|
15431
15529
|
return {
|
|
@@ -15434,11 +15532,18 @@ var ReplayService = class {
|
|
|
15434
15532
|
patchesApplied: 0,
|
|
15435
15533
|
patchesWithConflicts: 0,
|
|
15436
15534
|
patchesSkipped: 0,
|
|
15535
|
+
patchesReverted: revertedPatchIds.length,
|
|
15437
15536
|
conflicts: [],
|
|
15438
15537
|
wouldApply: newPatches,
|
|
15439
15538
|
warnings: warnings.length > 0 ? warnings : void 0
|
|
15440
15539
|
};
|
|
15441
15540
|
}
|
|
15541
|
+
for (const id of revertedPatchIds) {
|
|
15542
|
+
try {
|
|
15543
|
+
this.lockManager.removePatch(id);
|
|
15544
|
+
} catch {
|
|
15545
|
+
}
|
|
15546
|
+
}
|
|
15442
15547
|
const commitOpts = options ? {
|
|
15443
15548
|
cliVersion: options.cliVersion ?? "unknown",
|
|
15444
15549
|
generatorVersions: options.generatorVersions ?? {},
|
|
@@ -15472,12 +15577,12 @@ var ReplayService = class {
|
|
|
15472
15577
|
await this.committer.stageAll();
|
|
15473
15578
|
}
|
|
15474
15579
|
}
|
|
15475
|
-
return this.buildReport("no-patches", newPatches, results, options, warnings, rebaseCounts);
|
|
15580
|
+
return this.buildReport("no-patches", newPatches, results, options, warnings, rebaseCounts, void 0, revertedPatchIds.length);
|
|
15476
15581
|
}
|
|
15477
15582
|
async handleNormalRegeneration(options) {
|
|
15478
15583
|
if (options?.dryRun) {
|
|
15479
15584
|
const existingPatches2 = this.lockManager.getPatches();
|
|
15480
|
-
const newPatches2 = await this.detector.detectNewPatches();
|
|
15585
|
+
const { patches: newPatches2, revertedPatchIds: dryRunReverted } = await this.detector.detectNewPatches();
|
|
15481
15586
|
const warnings2 = [...this.detector.warnings];
|
|
15482
15587
|
const allPatches2 = [...existingPatches2, ...newPatches2];
|
|
15483
15588
|
return {
|
|
@@ -15486,13 +15591,19 @@ var ReplayService = class {
|
|
|
15486
15591
|
patchesApplied: 0,
|
|
15487
15592
|
patchesWithConflicts: 0,
|
|
15488
15593
|
patchesSkipped: 0,
|
|
15594
|
+
patchesReverted: dryRunReverted.length,
|
|
15489
15595
|
conflicts: [],
|
|
15490
15596
|
wouldApply: allPatches2,
|
|
15491
15597
|
warnings: warnings2.length > 0 ? warnings2 : void 0
|
|
15492
15598
|
};
|
|
15493
15599
|
}
|
|
15494
15600
|
let existingPatches = this.lockManager.getPatches();
|
|
15601
|
+
const preRebasePatchIds = new Set(existingPatches.map((p) => p.id));
|
|
15495
15602
|
const preRebaseCounts = await this.preGenerationRebase(existingPatches);
|
|
15603
|
+
const postRebasePatchIds = new Set(this.lockManager.getPatches().map((p) => p.id));
|
|
15604
|
+
const removedByPreRebase = existingPatches.filter(
|
|
15605
|
+
(p) => preRebasePatchIds.has(p.id) && !postRebasePatchIds.has(p.id)
|
|
15606
|
+
);
|
|
15496
15607
|
existingPatches = this.lockManager.getPatches();
|
|
15497
15608
|
const seenHashes = /* @__PURE__ */ new Set();
|
|
15498
15609
|
for (const p of existingPatches) {
|
|
@@ -15503,8 +15614,28 @@ var ReplayService = class {
|
|
|
15503
15614
|
}
|
|
15504
15615
|
}
|
|
15505
15616
|
existingPatches = this.lockManager.getPatches();
|
|
15506
|
-
|
|
15617
|
+
let { patches: newPatches, revertedPatchIds } = await this.detector.detectNewPatches();
|
|
15507
15618
|
const warnings = [...this.detector.warnings];
|
|
15619
|
+
if (removedByPreRebase.length > 0) {
|
|
15620
|
+
const removedOriginalCommits = new Set(removedByPreRebase.map((p) => p.original_commit));
|
|
15621
|
+
const removedOriginalMessages = new Set(removedByPreRebase.map((p) => p.original_message));
|
|
15622
|
+
newPatches = newPatches.filter((p) => {
|
|
15623
|
+
if (removedOriginalCommits.has(p.original_commit)) return false;
|
|
15624
|
+
if (isRevertCommit(p.original_message)) {
|
|
15625
|
+
const revertedMsg = parseRevertedMessage(p.original_message);
|
|
15626
|
+
if (revertedMsg && removedOriginalMessages.has(revertedMsg)) return false;
|
|
15627
|
+
}
|
|
15628
|
+
return true;
|
|
15629
|
+
});
|
|
15630
|
+
}
|
|
15631
|
+
for (const id of revertedPatchIds) {
|
|
15632
|
+
try {
|
|
15633
|
+
this.lockManager.removePatch(id);
|
|
15634
|
+
} catch {
|
|
15635
|
+
}
|
|
15636
|
+
}
|
|
15637
|
+
const revertedSet = new Set(revertedPatchIds);
|
|
15638
|
+
existingPatches = existingPatches.filter((p) => !revertedSet.has(p.id));
|
|
15508
15639
|
const allPatches = [...existingPatches, ...newPatches];
|
|
15509
15640
|
const commitOpts = options ? {
|
|
15510
15641
|
cliVersion: options.cliVersion ?? "unknown",
|
|
@@ -15549,7 +15680,8 @@ var ReplayService = class {
|
|
|
15549
15680
|
options,
|
|
15550
15681
|
warnings,
|
|
15551
15682
|
rebaseCounts,
|
|
15552
|
-
preRebaseCounts
|
|
15683
|
+
preRebaseCounts,
|
|
15684
|
+
revertedPatchIds.length
|
|
15553
15685
|
);
|
|
15554
15686
|
}
|
|
15555
15687
|
/**
|
|
@@ -15742,36 +15874,6 @@ var ReplayService = class {
|
|
|
15742
15874
|
}
|
|
15743
15875
|
return { conflictResolved, conflictAbsorbed, contentRefreshed };
|
|
15744
15876
|
}
|
|
15745
|
-
/**
|
|
15746
|
-
* Strip conflict markers from file content, keeping the OURS (Generated) side.
|
|
15747
|
-
* Preserves clean patches' non-conflicting changes on shared files.
|
|
15748
|
-
*/
|
|
15749
|
-
stripConflictMarkers(content) {
|
|
15750
|
-
const lines = content.split("\n");
|
|
15751
|
-
const result = [];
|
|
15752
|
-
let inConflict = false;
|
|
15753
|
-
let inOurs = false;
|
|
15754
|
-
for (const line of lines) {
|
|
15755
|
-
if (line.startsWith("<<<<<<< ")) {
|
|
15756
|
-
inConflict = true;
|
|
15757
|
-
inOurs = true;
|
|
15758
|
-
continue;
|
|
15759
|
-
}
|
|
15760
|
-
if (inConflict && line === "=======") {
|
|
15761
|
-
inOurs = false;
|
|
15762
|
-
continue;
|
|
15763
|
-
}
|
|
15764
|
-
if (inConflict && line.startsWith(">>>>>>> ")) {
|
|
15765
|
-
inConflict = false;
|
|
15766
|
-
inOurs = false;
|
|
15767
|
-
continue;
|
|
15768
|
-
}
|
|
15769
|
-
if (!inConflict || inOurs) {
|
|
15770
|
-
result.push(line);
|
|
15771
|
-
}
|
|
15772
|
-
}
|
|
15773
|
-
return result.join("\n");
|
|
15774
|
-
}
|
|
15775
15877
|
/**
|
|
15776
15878
|
* After applyPatches(), strip conflict markers from conflicting files
|
|
15777
15879
|
* so only clean content is committed. Keeps the Generated (OURS) side.
|
|
@@ -15784,7 +15886,7 @@ var ReplayService = class {
|
|
|
15784
15886
|
const filePath = (0, import_node_path4.join)(this.outputDir, fileResult.file);
|
|
15785
15887
|
try {
|
|
15786
15888
|
const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
|
|
15787
|
-
const stripped =
|
|
15889
|
+
const stripped = stripConflictMarkers(content);
|
|
15788
15890
|
(0, import_node_fs2.writeFileSync)(filePath, stripped);
|
|
15789
15891
|
} catch {
|
|
15790
15892
|
}
|
|
@@ -15796,7 +15898,7 @@ var ReplayService = class {
|
|
|
15796
15898
|
if (!(0, import_node_fs2.existsSync)(fernignorePath)) return [];
|
|
15797
15899
|
return (0, import_node_fs2.readFileSync)(fernignorePath, "utf-8").split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
15798
15900
|
}
|
|
15799
|
-
buildReport(flow, patches, results, options, warnings, rebaseCounts, preRebaseCounts) {
|
|
15901
|
+
buildReport(flow, patches, results, options, warnings, rebaseCounts, preRebaseCounts, patchesReverted) {
|
|
15800
15902
|
const conflictResults = results.filter((r) => r.status === "conflict");
|
|
15801
15903
|
const conflictDetails = conflictResults.map((r) => {
|
|
15802
15904
|
const conflictFiles = r.fileResults?.filter((f) => f.status === "conflict") ?? [];
|
|
@@ -15821,6 +15923,7 @@ var ReplayService = class {
|
|
|
15821
15923
|
patchesRepointed: rebaseCounts && rebaseCounts.repointed > 0 ? rebaseCounts.repointed : void 0,
|
|
15822
15924
|
patchesContentRebased: rebaseCounts && rebaseCounts.contentRebased > 0 ? rebaseCounts.contentRebased : void 0,
|
|
15823
15925
|
patchesKeptAsUserOwned: rebaseCounts && rebaseCounts.keptAsUserOwned > 0 ? rebaseCounts.keptAsUserOwned : void 0,
|
|
15926
|
+
patchesReverted: patchesReverted && patchesReverted > 0 ? patchesReverted : void 0,
|
|
15824
15927
|
patchesConflictResolved: preRebaseCounts && preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed > 0 ? preRebaseCounts.conflictResolved + preRebaseCounts.conflictAbsorbed : void 0,
|
|
15825
15928
|
patchesRefreshed: preRebaseCounts && preRebaseCounts.contentRefreshed > 0 ? preRebaseCounts.contentRefreshed : void 0,
|
|
15826
15929
|
conflicts: conflictResults.flatMap((r) => r.fileResults?.filter((f) => f.status === "conflict") ?? []),
|
|
@@ -15866,7 +15969,7 @@ var FernignoreMigrator = class {
|
|
|
15866
15969
|
async analyzeMigration() {
|
|
15867
15970
|
const patterns = this.readFernignorePatterns();
|
|
15868
15971
|
const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);
|
|
15869
|
-
const patches = await detector.detectNewPatches();
|
|
15972
|
+
const { patches } = await detector.detectNewPatches();
|
|
15870
15973
|
const trackedByBoth = [];
|
|
15871
15974
|
const fernignoreOnly = [];
|
|
15872
15975
|
const commitsOnly = [];
|
|
@@ -15991,7 +16094,7 @@ var FernignoreMigrator = class {
|
|
|
15991
16094
|
async migrate() {
|
|
15992
16095
|
const analysis = await this.analyzeMigration();
|
|
15993
16096
|
const detector = new ReplayDetector(this.git, this.lockManager, this.outputDir);
|
|
15994
|
-
const patches = await detector.detectNewPatches();
|
|
16097
|
+
const { patches } = await detector.detectNewPatches();
|
|
15995
16098
|
const warnings = [];
|
|
15996
16099
|
let patchesCreated = 0;
|
|
15997
16100
|
for (const patch of patches) {
|
|
@@ -16544,11 +16647,14 @@ async function runDetect(dir) {
|
|
|
16544
16647
|
lockManager.read();
|
|
16545
16648
|
const git = new GitClient(dir);
|
|
16546
16649
|
const detector = new ReplayDetector(git, lockManager, dir);
|
|
16547
|
-
const patches = await detector.detectNewPatches();
|
|
16650
|
+
const { patches, revertedPatchIds } = await detector.detectNewPatches();
|
|
16548
16651
|
if (detector.warnings.length > 0) {
|
|
16549
16652
|
for (const w of detector.warnings) console.log(`Warning: ${w}`);
|
|
16550
16653
|
console.log();
|
|
16551
16654
|
}
|
|
16655
|
+
if (revertedPatchIds.length > 0) {
|
|
16656
|
+
console.log(`Reverted patches: ${revertedPatchIds.length}`);
|
|
16657
|
+
}
|
|
16552
16658
|
console.log(`Detected ${patches.length} new patch(es) since last generation:
|
|
16553
16659
|
`);
|
|
16554
16660
|
if (patches.length === 0) {
|
|
@@ -16590,6 +16696,9 @@ function printReport(report) {
|
|
|
16590
16696
|
if (report.patchesKeptAsUserOwned) {
|
|
16591
16697
|
console.log(`Patches kept (user-owned files): ${report.patchesKeptAsUserOwned}`);
|
|
16592
16698
|
}
|
|
16699
|
+
if (report.patchesReverted) {
|
|
16700
|
+
console.log(`Patches reverted by user: ${report.patchesReverted}`);
|
|
16701
|
+
}
|
|
16593
16702
|
if (report.patchesPartiallyApplied) {
|
|
16594
16703
|
console.log(`Patches partially applied: ${report.patchesPartiallyApplied}`);
|
|
16595
16704
|
}
|