Skip to content

Commit 0915fca

Browse files
committed
Adopt workspace_integrate_upstream API in desktop app
**`IntegrateUpstreamModal` refactor:** - Migrated from old Resolution API to `BottomUpdate[]` API - Imperative status fetch → reactive `useQuery` subscription (auto-invalidates on background fetch) - Wrapped statuses section in `<ReduxResult>` for loading/error handling **Backend (`upstream_integration.rs`):** - Exposed `bottom_selector` on `StackStatus` for building `BottomUpdate`s **E2E tests:** - "Leave as is" preserves branch base while other branches advance - Helpers: `openIntegrateModal()`, `integrationRow()`, `getBranchBase()` **Cleanup:** - Merged `UpstreamIntegrationService` into `stackService` — upstream status queries and mutations now live alongside other stack operations - Removed `StackStatusesWithBranchesV3` type and `getBaseBranchResolution` (joining now happens in the modal) - Deleted old `integrate_upstream` endpoint and dead code in `branchEndpoints.ts` Return stack status entries instead of full stack objects The API already returns status entries keyed by stack ID, so adjust the component to use those entries directly instead of trying to join with a separate stacks list. This simplifies logic, avoids relying on getStackName/getStack lookup, and fixes incorrect data assumptions implied by combineWithStacks. Changes: parse status entries from the API, sort by integration state and branch name, update resolution kind handling, build BottomUpdate payloads from stack IDs, and update the template to iterate over status entries. Accept Option<StackId> throughout upstream status handling Revert earlier change that propagated StackId instead of Option<StackId> and instead update codepaths to continue accepting Optional stack IDs while preserving the optimizations made. Many functions, data structures, iterations and tests were adjusted to use StackStatus with an optional stack_id field (or to pattern-match the existing Option inside loops) so we can keep nullable stack identifiers at the API/schema boundary while simplifying internal handling and avoiding unwraps. Changes include: UI Svelte component iteration and resolution handling, Rust CLI/status/pull modules iteration and lookups, the StackStatus struct and serialization/schema updates, callers of get_stack_status to pass stack_id through, and numerous tests updated to reference status.stack_id instead of tuple-based (Option, Status) indexing. Use but-graph for workspace upstream statuses Replace legacy upstream integration path with a new implementation that uses the but-graph workspace projection to compute per-stack upstream integration statuses and worktree conflicts. This moves logic out of gitbutler-branch-actions into a new workspace/upstream_statuses module, updates callers to invoke the new function, and makes StackStatus::create public to support the new flow. The change avoids the old stack_details_v3 path and performs trial rebases and three-way merges against the graph-derived workspace to determine conflicts and integration state. Remove legacy upstream integration APIs and code Remove all callers and implementations of the legacy integrate_upstream and upstream statuses APIs. These endpoints and helper functions have been deleted from the server, tauri bindings, tests, and the gitbutler-branch-actions crate; upstream integration status computation and workspace integration are now handled by the newer workspace APIs (e.g. but_api::workspace::workspace_integrate_upstream and but_api::workspace::upstream_statuses). This cleans up dead legacy code, removes unused types and tests, and updates call sites to use the new workspace-oriented APIs. Move upstream integration types into but-api workspace Move the upstream integration types into but-api::workspace and update all callers to import them from the new location. This removes the legacy re-export from gitbutler-branch-actions and converts the workspace module to expose a dedicated upstream_integration submodule. The change updates imports across but, but-api, and gitbutler-branch-actions (including virtual_branches, status, and pull command code) to reference but_api::workspace::upstream_integration::{...} and wires upstream_statuses to use the relocated types.
1 parent a853ec7 commit 0915fca

23 files changed

Lines changed: 964 additions & 1543 deletions

File tree

apps/desktop/src/components/upstream/IntegrateUpstreamModal.svelte

Lines changed: 212 additions & 217 deletions
Large diffs are not rendered by default.

apps/desktop/src/lib/bootstrap/deps.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ import DataSharingService, { DATA_SHARING_SERVICE } from "$lib/support/dataShari
6060
import { EVENT_CONTEXT, EventContext } from "$lib/telemetry/eventContext";
6161
import { POSTHOG_WRAPPER, PostHogWrapper } from "$lib/telemetry/posthog";
6262
import { UPDATER_SERVICE, UpdaterService } from "$lib/updater/updater";
63-
import {
64-
UpstreamIntegrationService,
65-
UPSTREAM_INTEGRATION_SERVICE,
66-
} from "$lib/upstream/upstreamIntegrationService.svelte";
6763
import { TokenMemoryService } from "$lib/user/tokenMemoryService";
6864
import { USER_SERVICE, UserService } from "$lib/user/userService.svelte";
6965
import { WorktreeService, WORKTREE_SERVICE } from "$lib/worktree/worktreeService.svelte";
@@ -261,14 +257,6 @@ export function initDependencies(args: {
261257
const dependencyService = new DependencyService(worktreeService);
262258

263259
// ============================================================================
264-
// WORKFLOWS
265-
// ============================================================================
266-
267-
const upstreamIntegrationService = new UpstreamIntegrationService(
268-
clientState.backendApi,
269-
stackService,
270-
);
271-
272260
// ============================================================================
273261
// FEEDS & NOTIFICATIONS
274262
// ============================================================================
@@ -379,7 +367,6 @@ export function initDependencies(args: {
379367
[UNCOMMITTED_SERVICE, uncommittedService],
380368
[UPDATER_SERVICE, updaterService],
381369
[UPLOADS_SERVICE, uploadsService],
382-
[UPSTREAM_INTEGRATION_SERVICE, upstreamIntegrationService],
383370
[URL_SERVICE, urlService],
384371
[USER_SERVICE, userService],
385372
[WORKTREE_SERVICE, worktreeService],

apps/desktop/src/lib/branches/branchEndpoints.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ import type { ForgeProvider, RemoteBranchInfo } from "$lib/baseBranch/baseBranch
1010
import type { BackendEndpointBuilder } from "$lib/state/backendApi";
1111
import type { BaseBranch } from "@gitbutler/but-sdk";
1212
import type {
13-
BaseBranchResolution,
1413
BaseBranchResolutionApproach,
1514
BranchListing,
1615
BranchListingDetails,
17-
IntegrationOutcome,
18-
Resolution,
1916
StackStatuses,
2017
} from "@gitbutler/but-sdk";
2118

@@ -111,25 +108,6 @@ export function buildBranchEndpoints(build: BackendEndpointBuilder) {
111108
query: (args) => args,
112109
providesTags: [providesList(ReduxTag.UpstreamIntegrationStatus)],
113110
}),
114-
integrateUpstream: build.mutation<
115-
IntegrationOutcome,
116-
{
117-
projectId: string;
118-
resolutions: Resolution[];
119-
baseBranchResolution?: BaseBranchResolution;
120-
}
121-
>({
122-
extraOptions: {
123-
command: "integrate_upstream",
124-
actionName: "Integrate Upstream",
125-
},
126-
query: (args) => args,
127-
invalidatesTags: [
128-
invalidatesList(ReduxTag.UpstreamIntegrationStatus),
129-
invalidatesList(ReduxTag.HeadSha),
130-
invalidatesList(ReduxTag.BranchListing),
131-
],
132-
}),
133111
resolveUpstreamIntegration: build.mutation<
134112
string,
135113
{ projectId: string; resolutionApproach: BaseBranchResolutionApproach }

apps/desktop/src/lib/stacks/stackEndpoints.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import type {
3939
UncommitResult,
4040
InsertSide,
4141
RelativeTo,
42+
BottomUpdate,
43+
WorkspaceState,
4244
} from "@gitbutler/but-sdk";
4345

4446
export type BranchParams = {
@@ -931,5 +933,21 @@ export function buildStackEndpoints(build: BackendEndpointBuilder) {
931933
extraOptions: { command: "pr_template" },
932934
query: (args) => args,
933935
}),
936+
workspaceIntegrateUpstream: build.mutation<
937+
WorkspaceState,
938+
{ projectId: string; updates: BottomUpdate[]; dryRun: boolean }
939+
>({
940+
extraOptions: {
941+
command: "workspace_integrate_upstream",
942+
actionName: "Integrate Upstream (Workspace)",
943+
},
944+
query: (args) => args,
945+
invalidatesTags: [
946+
invalidatesList(ReduxTag.HeadSha),
947+
invalidatesList(ReduxTag.WorktreeChanges),
948+
invalidatesList(ReduxTag.Stacks),
949+
invalidatesList(ReduxTag.UpstreamIntegrationStatus),
950+
],
951+
}),
934952
};
935953
}

apps/desktop/src/lib/stacks/stackService.svelte.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,21 @@ export class StackService {
578578
return this.backendApi.endpoints.unapply.mutate;
579579
}
580580

581+
get workspaceIntegrateUpstream() {
582+
return this.backendApi.endpoints.workspaceIntegrateUpstream.mutate;
583+
}
584+
585+
upstreamStatusesQuery(projectId: string, targetCommitOid: string | undefined) {
586+
return this.backendApi.endpoints.upstreamIntegrationStatuses.useQuery({
587+
projectId,
588+
targetCommitOid,
589+
});
590+
}
591+
592+
get resolveUpstreamIntegrationMutation() {
593+
return this.backendApi.endpoints.resolveUpstreamIntegration.mutate;
594+
}
595+
581596
get discardChanges() {
582597
return this.backendApi.endpoints.discardChanges.mutate;
583598
}

apps/desktop/src/lib/upstream/types.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.

apps/desktop/src/lib/upstream/upstreamIntegrationService.svelte.ts

Lines changed: 0 additions & 59 deletions
This file was deleted.

crates/but-api/src/legacy/virtual_branches.rs

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ use gitbutler_branch::{BranchCreateRequest, BranchUpdateRequest};
1414
use gitbutler_branch_actions::{
1515
BaseBranch, BranchListing, BranchListingDetails, BranchListingFilter,
1616
branch_upstream_integration::IntegrationStrategy,
17-
upstream_integration::{
18-
BaseBranchResolution, BaseBranchResolutionApproach, IntegrationOutcome, Resolution,
19-
StackStatuses,
20-
},
2117
};
18+
19+
use crate::workspace::upstream_integration::StackStatuses;
2220
use gitbutler_git::GitContextExt as _;
2321
use gitbutler_operating_modes::ensure_open_workspace_mode;
2422
use gitbutler_project::FetchResult;
@@ -670,8 +668,6 @@ pub async fn upstream_integration_statuses(
670668
) -> Result<StackStatuses> {
671669
let (base_branch, commit_id, ctx) = {
672670
let ctx = ctx.into_thread_local();
673-
674-
// Get all the actively applied reviews
675671
(
676672
gitbutler_branch_actions::base::get_base_branch_data(&ctx)?,
677673
target_commit_id,
@@ -681,52 +677,11 @@ pub async fn upstream_integration_statuses(
681677

682678
let resolved_reviews = resolve_review_map(ctx.clone(), &base_branch).await?;
683679
let mut ctx = ctx.into_thread_local();
684-
gitbutler_branch_actions::upstream_integration_statuses(&mut ctx, commit_id, &resolved_reviews)
685-
}
686-
687-
#[but_api]
688-
#[instrument(err(Debug))]
689-
pub async fn integrate_upstream(
690-
ctx: ThreadSafeContext,
691-
resolutions: Vec<Resolution>,
692-
base_branch_resolution: Option<BaseBranchResolution>,
693-
) -> Result<IntegrationOutcome> {
694-
let (base_branch, ctx) = {
695-
let ctx = ctx.into_thread_local();
696-
let base_branch = gitbutler_branch_actions::base::get_base_branch_data(&ctx)?;
697-
(base_branch, ctx.to_sync())
698-
};
699-
let resolved_reviews = resolve_review_map(ctx.clone(), &base_branch).await?;
700-
let mut ctx = ctx.into_thread_local();
701-
let outcome = gitbutler_branch_actions::integrate_upstream(
702-
&mut ctx,
703-
&resolutions,
704-
base_branch_resolution,
705-
&resolved_reviews,
706-
)?;
707-
708-
Ok(outcome)
709-
}
710-
711-
#[but_api]
712-
#[instrument(err(Debug))]
713-
pub async fn resolve_upstream_integration(
714-
ctx: ThreadSafeContext,
715-
resolution_approach: BaseBranchResolutionApproach,
716-
) -> Result<String> {
717-
let (base_branch, sync_ctx) = {
718-
let ctx = ctx.into_thread_local();
719-
let base_branch = gitbutler_branch_actions::base::get_base_branch_data(&ctx)?;
720-
(base_branch, ctx.into_sync())
721-
};
722-
let resolved_reviews = resolve_review_map(sync_ctx.clone(), &base_branch).await?;
723-
let mut ctx = sync_ctx.into_thread_local();
724-
let new_target_id = gitbutler_branch_actions::resolve_upstream_integration(
680+
crate::workspace::workspace_upstream_integration_statuses(
725681
&mut ctx,
726-
resolution_approach,
682+
commit_id,
727683
&resolved_reviews,
728-
)?;
729-
Ok(new_target_id.to_string())
684+
)
730685
}
731686

732687
/// Resolve all actively applied reviews for the given project and command context
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ use but_oplog::legacy::{OperationKind, SnapshotDetails};
77
use but_workspace::IntegrateUpstreamOutcome;
88
use tracing::instrument;
99

10+
pub mod upstream_integration;
11+
12+
mod upstream_statuses;
13+
pub use upstream_statuses::workspace_upstream_integration_statuses;
14+
1015
/// JSON transport types for workspace APIs.
1116
pub mod json {
1217
use serde::{Deserialize, Serialize};

0 commit comments

Comments
 (0)