feat: add relay reconnect with grace period and branch suggestions
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildBranchComboOptions, normalizeBranchOptionName } from "./branch-suggestions";
|
||||
|
||||
describe("normalizeBranchOptionName", () => {
|
||||
it("normalizes local and origin-prefixed refs", () => {
|
||||
expect(normalizeBranchOptionName("refs/heads/main")).toBe("main");
|
||||
expect(normalizeBranchOptionName("refs/remotes/origin/main")).toBe("main");
|
||||
expect(normalizeBranchOptionName("origin/feature/test")).toBe("feature/test");
|
||||
expect(normalizeBranchOptionName("feature/test")).toBe("feature/test");
|
||||
});
|
||||
|
||||
it("filters out empty values and HEAD", () => {
|
||||
expect(normalizeBranchOptionName("")).toBeNull();
|
||||
expect(normalizeBranchOptionName(" ")).toBeNull();
|
||||
expect(normalizeBranchOptionName("HEAD")).toBeNull();
|
||||
expect(normalizeBranchOptionName("origin/HEAD")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildBranchComboOptions", () => {
|
||||
it("merges branch sources and de-duplicates normalized names", () => {
|
||||
const options = buildBranchComboOptions({
|
||||
suggestedBranches: ["origin/main", "refs/remotes/origin/main", "feature/a"],
|
||||
currentBranch: "refs/heads/feature/a",
|
||||
baseRef: "origin/main",
|
||||
typedBaseBranch: "main",
|
||||
worktreeBranchLabels: ["refs/heads/release/next"],
|
||||
});
|
||||
|
||||
expect(options).toEqual([
|
||||
{ id: "main", label: "main" },
|
||||
{ id: "feature/a", label: "feature/a" },
|
||||
{ id: "release/next", label: "release/next" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
export type BranchComboOption = {
|
||||
id: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export function normalizeBranchOptionName(input: string | null | undefined): string | null {
|
||||
const trimmed = input?.trim();
|
||||
if (!trimmed || trimmed === "HEAD") {
|
||||
return null;
|
||||
}
|
||||
|
||||
let normalized = trimmed;
|
||||
if (normalized.startsWith("refs/heads/")) {
|
||||
normalized = normalized.slice("refs/heads/".length);
|
||||
} else if (normalized.startsWith("refs/remotes/")) {
|
||||
normalized = normalized.slice("refs/remotes/".length);
|
||||
}
|
||||
if (normalized.startsWith("origin/")) {
|
||||
normalized = normalized.slice("origin/".length);
|
||||
}
|
||||
|
||||
return normalized.length > 0 && normalized !== "HEAD" ? normalized : null;
|
||||
}
|
||||
|
||||
export function buildBranchComboOptions(input: {
|
||||
suggestedBranches?: string[];
|
||||
currentBranch?: string | null;
|
||||
baseRef?: string | null;
|
||||
typedBaseBranch?: string | null;
|
||||
worktreeBranchLabels?: string[];
|
||||
}): BranchComboOption[] {
|
||||
const branchSet = new Set<string>();
|
||||
const addBranch = (name: string | null | undefined) => {
|
||||
const normalized = normalizeBranchOptionName(name);
|
||||
if (normalized) {
|
||||
branchSet.add(normalized);
|
||||
}
|
||||
};
|
||||
|
||||
for (const branch of input.suggestedBranches ?? []) {
|
||||
addBranch(branch);
|
||||
}
|
||||
addBranch(input.currentBranch ?? null);
|
||||
addBranch(input.baseRef ?? null);
|
||||
addBranch(input.typedBaseBranch ?? null);
|
||||
for (const label of input.worktreeBranchLabels ?? []) {
|
||||
addBranch(label);
|
||||
}
|
||||
|
||||
return Array.from(branchSet).map((name) => ({ id: name, label: name }));
|
||||
}
|
||||
Reference in New Issue
Block a user