Fix merge base commit for fast-forwarded GitLab PRs (#27825)

Due to a bug in the GitLab API, the diff_refs field is populated in the
response when fetching an individual merge request, but not when
fetching a list of them. That field is used to populate the merge base
commit SHA.
While there is detection for the merge base even when not populated by
the downloader, that detection is not flawless. Specifically, when a
GitLab merge request has a single commit, and gets merged with the
squash strategy, the base branch will be fast-forwarded instead of a
separate squash or merge commit being created. The merge base detection
attempts to find the last commit on the base branch that is also on the
PR branch, but in the fast-forward case that is the PR's only commit.
Assuming the head commit is also the merge base results in the import of
a PR with 0 commits and no diff.

This PR uses the individual merge request endpoint to fetch merge
request data with the diff_refs field. With its data, the base merge
commit can be properly set, which—by not relying on the detection
mentioned above—correctly imports PRs that were "merged" by
fast-forwarding the base branch.

ref: https://gitlab.com/gitlab-org/gitlab/-/issues/29620
This commit is contained in:
Sebastian Brückner 2023-10-29 13:29:33 +00:00 committed by GitHub
parent 641e8165c7
commit 02dae3f84b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -528,11 +528,13 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
perPage = g.maxPerPage perPage = g.maxPerPage
} }
view := "simple"
opt := &gitlab.ListProjectMergeRequestsOptions{ opt := &gitlab.ListProjectMergeRequestsOptions{
ListOptions: gitlab.ListOptions{ ListOptions: gitlab.ListOptions{
PerPage: perPage, PerPage: perPage,
Page: page, Page: page,
}, },
View: &view,
} }
allPRs := make([]*base.PullRequest, 0, perPage) allPRs := make([]*base.PullRequest, 0, perPage)
@ -541,7 +543,13 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
if err != nil { if err != nil {
return nil, false, fmt.Errorf("error while listing merge requests: %w", err) return nil, false, fmt.Errorf("error while listing merge requests: %w", err)
} }
for _, pr := range prs { for _, simplePR := range prs {
// Load merge request again by itself, as not all fields are populated in the ListProjectMergeRequests endpoint.
// See https://gitlab.com/gitlab-org/gitlab/-/issues/29620
pr, _, err := g.client.MergeRequests.GetMergeRequest(g.repoID, simplePR.IID, nil)
if err != nil {
return nil, false, fmt.Errorf("error while loading merge request: %w", err)
}
labels := make([]*base.Label, 0, len(pr.Labels)) labels := make([]*base.Label, 0, len(pr.Labels))
for _, l := range pr.Labels { for _, l := range pr.Labels {