Skip to content

Commit 7a2e646

Browse files
committed
Use head_info rather than stacks or stack_details when possible
We still need some usage of `stacks` for the branch listing page AFAIK, but using `head_info` for the main projection is a big help since it avoids the issues with some strange inconsistency issues between `stack_details` and `stacks`.
1 parent cec2bc9 commit 7a2e646

7 files changed

Lines changed: 589 additions & 109 deletions

File tree

apps/desktop/src/components/branchesPage/BranchesViewStack.svelte

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
3131
const stackService = inject(STACK_SERVICE);
3232
33-
const stackQuery = $derived(stackService.allStackById(projectId, stackId));
33+
const stackQuery = $derived(stackService.branchesPageStack(projectId, stackId, inWorkspace));
3434
</script>
3535

3636
<ReduxResult result={stackQuery.result} {projectId} {stackId} {onerror}>
@@ -39,7 +39,12 @@
3939
<p>Stack not found.</p>
4040
{:else}
4141
{#each getStackBranchNames(stack) as branchName, idx}
42-
{@const branchDetailsQuery = stackService.branchDetails(projectId, stackId, branchName)}
42+
{@const branchDetailsQuery = stackService.branchesPageBranchDetails(
43+
projectId,
44+
stackId,
45+
branchName,
46+
inWorkspace,
47+
)}
4348
{@const branchDetails = branchDetailsQuery.response}
4449
{@const lineColor = branchDetails
4550
? getColorFromPushStatus(branchDetails.pushStatus)
@@ -55,6 +60,7 @@
5560
{branchName}
5661
isTopBranch={idx === 0}
5762
{inWorkspace}
63+
branchesPage
5864
{isTarget}
5965
{selectedCommitId}
6066
{onCommitClick}

apps/desktop/src/components/views/BranchesViewBranch.svelte

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
isTopBranch?: boolean;
2121
isTarget?: boolean;
2222
inWorkspace?: boolean;
23+
branchesPage?: boolean;
2324
selectedCommitId?: string;
2425
onCommitClick: (commitId: string) => void;
2526
onFileClick: (index: number) => void;
@@ -33,6 +34,7 @@
3334
remote,
3435
isTopBranch = true,
3536
inWorkspace,
37+
branchesPage = false,
3638
isTarget,
3739
selectedCommitId,
3840
onCommitClick,
@@ -42,9 +44,11 @@
4244
4345
const stackService = inject(STACK_SERVICE);
4446
const branchQuery = $derived(
45-
stackId
46-
? stackService.branchDetails(projectId, stackId, branchName)
47-
: stackService.unstackedBranchDetails(projectId, branchName, remote),
47+
stackId && branchesPage
48+
? stackService.branchesPageBranchDetails(projectId, stackId, branchName, inWorkspace ?? false)
49+
: stackId
50+
? stackService.branchDetails(projectId, stackId, branchName)
51+
: stackService.unstackedBranchDetails(projectId, branchName, remote),
4852
);
4953
5054
let cherryApplyModal = $state<CherryApplyModal>();
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { transformWorkspaceDetails } from "$lib/stacks/headInfoAdapters";
2+
import { describe, expect, test } from "vitest";
3+
import type { Author, Commit, RefInfo, Segment, UpstreamCommit } from "@gitbutler/but-sdk";
4+
5+
const encoder = new TextEncoder();
6+
7+
function bytes(value: string): number[] {
8+
return [...encoder.encode(value)];
9+
}
10+
11+
const author: Author = {
12+
name: "Ada",
13+
email: "ada@example.com",
14+
gravatarUrl: "",
15+
};
16+
17+
const localCommit: Commit = {
18+
id: "1111111111111111111111111111111111111111",
19+
parentIds: ["0000000000000000000000000000000000000000"],
20+
message: "Local commit",
21+
hasConflicts: true,
22+
state: { type: "LocalOnly" },
23+
createdAt: 1000,
24+
author,
25+
changeId: "I111",
26+
gerritReviewUrl: null,
27+
};
28+
29+
const upstreamCommit: UpstreamCommit = {
30+
id: "2222222222222222222222222222222222222222",
31+
message: "Remote commit",
32+
createdAt: 2000,
33+
author,
34+
changeId: "I222",
35+
};
36+
37+
function segment(overrides: Partial<Segment> = {}): Segment {
38+
return {
39+
refName: {
40+
fullNameBytes: bytes("refs/heads/feature/top"),
41+
displayName: "feature/top",
42+
},
43+
remoteTrackingRefName: {
44+
fullNameBytes: bytes("refs/remotes/origin/feature/top"),
45+
displayName: "feature/top",
46+
remoteName: "origin",
47+
},
48+
commits: [localCommit],
49+
commitsOnRemote: [upstreamCommit],
50+
commitsOutside: null,
51+
metadata: {
52+
refInfo: {
53+
createdAt: null,
54+
updatedAt: { seconds: 123, offset: 0 },
55+
},
56+
review: {
57+
pullRequest: 7,
58+
reviewId: "review-7",
59+
},
60+
},
61+
isEntrypoint: true,
62+
pushStatus: "unpushedCommits",
63+
base: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
64+
...overrides,
65+
};
66+
}
67+
68+
function refInfo(stacks: RefInfo["stacks"]): RefInfo {
69+
return {
70+
workspaceRef: null,
71+
stacks,
72+
target: null,
73+
isManagedRef: true,
74+
isManagedCommit: true,
75+
isEntrypoint: true,
76+
};
77+
}
78+
79+
describe("headInfoAdapters", () => {
80+
test("maps head_info stacks to legacy stack entries and stack details", () => {
81+
const result = transformWorkspaceDetails(
82+
refInfo([
83+
{
84+
id: "stack-1",
85+
base: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
86+
segments: [segment()],
87+
},
88+
]),
89+
);
90+
91+
expect(result.stacks.ids).toEqual(["stack-1"]);
92+
expect(result.stacks.entities["stack-1"]).toMatchObject({
93+
id: "stack-1",
94+
tip: localCommit.id,
95+
order: 0,
96+
isCheckedOut: true,
97+
heads: [
98+
{
99+
name: "feature/top",
100+
tip: localCommit.id,
101+
reviewId: 7,
102+
isCheckedOut: true,
103+
},
104+
],
105+
});
106+
107+
const details = result.stackDetails["stack-1"]!;
108+
expect(details.stackInfo).toMatchObject({
109+
derivedName: "feature/top",
110+
pushStatus: "unpushedCommits",
111+
isConflicted: true,
112+
});
113+
expect(details.stackInfo.branchDetails[0]).toMatchObject({
114+
name: "feature/top",
115+
reference: "refs/heads/feature/top",
116+
remoteTrackingBranch: "refs/remotes/origin/feature/top",
117+
prNumber: 7,
118+
reviewId: "review-7",
119+
tip: localCommit.id,
120+
baseCommit: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
121+
lastUpdatedAt: 123000,
122+
commits: [localCommit],
123+
upstreamCommits: [upstreamCommit],
124+
isRemoteHead: false,
125+
});
126+
expect(details.commits.ids).toEqual([localCommit.id]);
127+
expect(details.upstreamCommits.ids).toEqual([upstreamCommit.id]);
128+
});
129+
130+
test("uses the stack base as the tip for empty segments", () => {
131+
const result = transformWorkspaceDetails(
132+
refInfo([
133+
{
134+
id: "stack-1",
135+
base: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
136+
segments: [
137+
segment({
138+
commits: [],
139+
base: null,
140+
}),
141+
],
142+
},
143+
]),
144+
);
145+
146+
expect(result.stacks.entities["stack-1"]?.tip).toBe("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
147+
expect(result.stackDetails["stack-1"]?.stackInfo.branchDetails[0]?.tip).toBe(
148+
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
149+
);
150+
});
151+
});

0 commit comments

Comments
 (0)