Skip to content

Commit f421a77

Browse files
authored
feat(gitprovider/gitlab): Support for squash merge and fast forward
Signed-off-by: GitHub <noreply@github.com>
1 parent 41252b5 commit f421a77

File tree

2 files changed

+100
-2
lines changed

2 files changed

+100
-2
lines changed

pkg/gitprovider/gitlab/gitlab.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,39 @@ func (p *provider) GetCommitURL(repoURL string, sha string) (string, error) {
260260
}
261261

262262
func convertGitlabMR(glMR gitlab.BasicMergeRequest) gitprovider.PullRequest {
263+
var merged = glMR.State == "merged"
264+
var mergeCommit string
265+
if merged {
266+
switch {
267+
case glMR.MergeCommitSHA != "":
268+
// Regular merge (with or without squash):
269+
// GitLab gives us the merge commit SHA.
270+
mergeCommit = glMR.MergeCommitSHA
271+
case glMR.SquashCommitSHA != "":
272+
// Fast-forward with squash:
273+
// No merge commit exists, but a squash commit SHA may be available.
274+
//
275+
// Note: GitLab does not reliably populate squash_commit_sha in all
276+
// relevant API/webhook payloads yet. We still prefer it when present,
277+
// and keep this branch to future-proof against incoming GitLab changes
278+
// that aim to backfill and correctly populate squash_commit_sha.
279+
//
280+
// References:
281+
// - https://gitlab.com/gitlab-org/gitlab/-/issues/415449
282+
// - https://gitlab.com/gitlab-org/gitlab/-/issues/294257
283+
mergeCommit = glMR.SquashCommitSHA
284+
default:
285+
// Fast-forward without squash:
286+
// No merge commit exists; the source HEAD is now on the target branch.
287+
mergeCommit = glMR.SHA
288+
}
289+
}
263290
return gitprovider.PullRequest{
264291
Number: glMR.IID,
265292
URL: glMR.WebURL,
266293
Open: isMROpen(glMR),
267-
Merged: glMR.State == "merged",
268-
MergeCommitSHA: glMR.MergeCommitSHA,
294+
Merged: merged,
295+
MergeCommitSHA: mergeCommit,
269296
Object: glMR,
270297
HeadSHA: glMR.SHA,
271298
CreatedAt: glMR.CreatedAt,

pkg/gitprovider/gitlab/gitlab_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,77 @@ func TestMergePullRequest(t *testing.T) {
384384
}
385385
}
386386

387+
func TestConvertGitlabMR_MergeCommitSelection(t *testing.T) {
388+
testCases := []struct {
389+
name string
390+
glMR gitlab.BasicMergeRequest
391+
expectedMerged bool
392+
expectedMergeCommit string
393+
}{
394+
{
395+
name: "merged - prefers MergeCommitSHA when present",
396+
glMR: gitlab.BasicMergeRequest{
397+
IID: 1,
398+
State: "merged",
399+
MergeCommitSHA: "merge_sha",
400+
SquashCommitSHA: "squash_sha",
401+
SHA: "head_sha",
402+
WebURL: "https://gitlab.com/group/project/-/merge_requests/1",
403+
},
404+
expectedMerged: true,
405+
expectedMergeCommit: "merge_sha",
406+
},
407+
{
408+
name: "merged - falls back to SquashCommitSHA when MergeCommitSHA is empty",
409+
glMR: gitlab.BasicMergeRequest{
410+
IID: 2,
411+
State: "merged",
412+
SquashCommitSHA: "squash_sha",
413+
SHA: "head_sha",
414+
WebURL: "https://gitlab.com/group/project/-/merge_requests/2",
415+
},
416+
expectedMerged: true,
417+
expectedMergeCommit: "squash_sha",
418+
},
419+
{
420+
name: "merged - falls back to SHA when both MergeCommitSHA and SquashCommitSHA are empty",
421+
glMR: gitlab.BasicMergeRequest{
422+
IID: 3,
423+
State: "merged",
424+
SHA: "head_sha",
425+
WebURL: "https://gitlab.com/group/project/-/merge_requests/3",
426+
},
427+
expectedMerged: true,
428+
expectedMergeCommit: "head_sha",
429+
},
430+
{
431+
name: "not merged - merge commit is empty regardless of fields",
432+
glMR: gitlab.BasicMergeRequest{
433+
IID: 4,
434+
State: "opened",
435+
MergeCommitSHA: "merge_sha",
436+
SquashCommitSHA: "squash_sha",
437+
SHA: "head_sha",
438+
WebURL: "https://gitlab.com/group/project/-/merge_requests/4",
439+
},
440+
expectedMerged: false,
441+
expectedMergeCommit: "",
442+
},
443+
}
444+
445+
for _, tc := range testCases {
446+
t.Run(tc.name, func(t *testing.T) {
447+
pr := convertGitlabMR(tc.glMR)
448+
449+
require.Equal(t, tc.expectedMerged, pr.Merged)
450+
require.Equal(t, tc.expectedMergeCommit, pr.MergeCommitSHA)
451+
require.Equal(t, tc.glMR.IID, pr.Number)
452+
require.Equal(t, tc.glMR.WebURL, pr.URL)
453+
require.Equal(t, tc.glMR.SHA, pr.HeadSHA)
454+
})
455+
}
456+
}
457+
387458
func TestParseGitLabURL(t *testing.T) {
388459
const expectedProjectName = "akuity/kargo"
389460
testCases := []struct {

0 commit comments

Comments
 (0)