feat(FN-4069): add direct merge commit routing to merger
Adds direct merge commit routing to the merger, allowing non-squash merges to bypass the squash-audit path when configured. The feature includes new `mergeCommitStrategy` settings, updated dashboard UI, expanded merger lifecycle tests, and documentation. Fusion-Task-Id: FN-4069
This commit is contained in:
@@ -3682,10 +3682,36 @@ export function SettingsModal({
|
||||
<details className="settings-option-details">
|
||||
<summary>More details</summary>
|
||||
<small>
|
||||
Controls what happens after a task reaches In Review. Direct mode preserves Fusion's current local squash-merge behavior. Pull request mode keeps the task in In Review while Fusion waits for GitHub reviews and required checks before merging the PR.
|
||||
Controls what happens after a task reaches In Review. Direct mode merges into the current branch locally. Pull request mode keeps the task in In Review while Fusion waits for GitHub reviews and required checks before merging the PR.
|
||||
</small>
|
||||
</details>
|
||||
</div>
|
||||
{form.mergeStrategy !== "pull-request" && (
|
||||
<div className="form-group">
|
||||
<label htmlFor="directMergeCommitStrategy">Direct merge commit routing</label>
|
||||
<select
|
||||
id="directMergeCommitStrategy"
|
||||
className="select"
|
||||
value={form.directMergeCommitStrategy ?? "auto"}
|
||||
onChange={(e) =>
|
||||
setForm((f) => ({
|
||||
...f,
|
||||
directMergeCommitStrategy: e.target.value as "auto" | "always-squash" | "always-rebase",
|
||||
}))
|
||||
}
|
||||
>
|
||||
<option value="auto">Auto — squash single-substantive branches, preserve multi-substantive history</option>
|
||||
<option value="always-squash">Always squash direct merges</option>
|
||||
<option value="always-rebase">Always preserve direct-merge commit history</option>
|
||||
</select>
|
||||
<details className="settings-option-details">
|
||||
<summary>More details</summary>
|
||||
<small>
|
||||
Auto keeps today's squash behavior for branches with zero or one substantive commit, but switches multi-substantive branches to a history-preserving rebase-and-merge path. Individual tasks can override this in PROMPT.md with <code>**Direct Merge Commit Strategy:** auto|always-squash|always-rebase</code>.
|
||||
</small>
|
||||
</details>
|
||||
</div>
|
||||
)}
|
||||
{form.mergeStrategy === "pull-request" && (
|
||||
<div className="form-group">
|
||||
<label htmlFor="requirePrApproval" className="checkbox-label">
|
||||
|
||||
@@ -177,6 +177,7 @@ const defaultSettings = {
|
||||
overlapIgnorePaths: [],
|
||||
autoMerge: true,
|
||||
mergeStrategy: "direct",
|
||||
directMergeCommitStrategy: "auto",
|
||||
pushAfterMerge: false,
|
||||
pushRemote: "origin",
|
||||
verificationFixRetries: 2,
|
||||
@@ -248,6 +249,17 @@ describe("SettingsModal", () => {
|
||||
expect(container.querySelectorAll(".settings-section-heading").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("shows direct merge commit routing only for direct merges", async () => {
|
||||
renderModal();
|
||||
await waitForSettingsModalReady();
|
||||
|
||||
await userEvent.click(screen.getByRole("button", { name: /^Merge$/ }));
|
||||
expect(screen.getByLabelText("Direct merge commit routing")).toHaveValue("auto");
|
||||
|
||||
await userEvent.selectOptions(screen.getByLabelText("Auto-completion mode"), "pull-request");
|
||||
expect(screen.queryByLabelText("Direct merge commit routing")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
clearPluginUiSlotsCache();
|
||||
|
||||
@@ -15,6 +15,7 @@ const defaultSettings = {
|
||||
groupOverlappingFiles: false,
|
||||
autoMerge: true,
|
||||
mergeStrategy: "direct",
|
||||
directMergeCommitStrategy: "auto",
|
||||
pushAfterMerge: false,
|
||||
pushRemote: "origin",
|
||||
recycleWorktrees: false,
|
||||
|
||||
Reference in New Issue
Block a user