Skip to content

Commit edb2b84

Browse files
committed
feat(gitlab): support rebase / squash merge method for MR
1 parent f2597c7 commit edb2b84

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

apps/desktop/src/lib/forge/gitlab/gitlabPrService.svelte.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,58 @@ function injectEndpoints(api: GitLabApi) {
146146
invalidatesTags: (result) => [invalidatesItem(ReduxTag.GitLabPullRequests, result?.number)]
147147
}),
148148
mergePr: build.mutation<undefined, { number: number; method: MergeMethod }>({
149-
queryFn: async ({ number }, query) => {
149+
queryFn: async ({ number, method }, query) => {
150150
try {
151151
const { api, upstreamProjectId } = gitlab(query.extra);
152-
await api.MergeRequests.merge(upstreamProjectId, number);
152+
153+
// Note: Unlike GitHub, GitLab's rebase is a two-step async process
154+
if (method === 'rebase') {
155+
// Rebase the source branch onto the target branch
156+
// This is an async operation that returns immediately with 202 status
157+
await api.MergeRequests.rebase(upstreamProjectId, number, {
158+
skipCI: false
159+
});
160+
161+
// Poll for rebase completion before merging
162+
// GitLab's rebase operation is asynchronous, so we need to wait
163+
const maxAttempts = 30; // 30 seconds timeout
164+
let attempt = 0;
165+
166+
while (attempt < maxAttempts) {
167+
// Check rebase status immediately (first iteration) or after waiting
168+
const mr = await api.MergeRequests.show(upstreamProjectId, number, {
169+
includeRebaseInProgress: true
170+
});
171+
172+
// Check if rebase completed successfully
173+
if (!mr.rebase_in_progress) {
174+
// Check for rebase errors
175+
if (mr.merge_error) {
176+
throw new Error(`Rebase failed: ${mr.merge_error}`);
177+
}
178+
break;
179+
}
180+
181+
attempt++;
182+
if (attempt >= maxAttempts) {
183+
throw new Error('Rebase operation timed out. Please try merging again later.');
184+
}
185+
186+
await sleep(1000);
187+
}
188+
189+
// After rebase completes successfully, perform the merge
190+
await api.MergeRequests.merge(upstreamProjectId, number, {
191+
shouldRemoveSourceBranch: true
192+
});
193+
} else {
194+
// For 'merge' and 'squash' methods, use the merge API directly
195+
await api.MergeRequests.merge(upstreamProjectId, number, {
196+
squash: method === 'squash',
197+
shouldRemoveSourceBranch: true
198+
});
199+
}
200+
153201
return { data: undefined };
154202
} catch (e: unknown) {
155203
return { error: toSerializable(e) };

0 commit comments

Comments
 (0)