rin
Public Open-source lightweight git hosting.
merge.go · 60 lines · 1.8 KB
Raw
1 package repo
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "polar/internal/git"
9 )
10
11 var ErrForkNotFound = errors.New("fork repository not found")
12
13 // MergePullRequest merges an open pull request into its base branch and
14 // records the merge. Same-repository pull requests merge local branches;
15 // cross-repository (fork) pull requests are merged through a temporary ref
16 // fetched from the fork.
17 func (s *Service) MergePullRequest(ctx context.Context, base *Repository, pr *PullRequest, authorName, authorEmail string, mergedByID int64) error {
18 if pr == nil || base == nil {
19 return errors.New("pull request and repository are required")
20 }
21 if pr.Status != "open" {
22 return errors.New("only open pull requests can be merged")
23 }
24
25 baseDisk, err := s.DiskPath(base.OwnerUsername, base.Name)
26 if err != nil {
27 return err
28 }
29
30 headLabel := pr.HeadBranch
31 if pr.HeadRepoID != nil && *pr.HeadRepoID != base.ID {
32 headLabel = fmt.Sprintf("%s/%s:%s", pr.HeadRepoOwner, pr.HeadRepoName, pr.HeadBranch)
33 }
34 msg := fmt.Sprintf("Merge pull request #%d from %s\n\n%s", pr.Number, headLabel, pr.Title)
35
36 if pr.HeadRepoID != nil && *pr.HeadRepoID != base.ID {
37 head, err := s.GetByID(ctx, *pr.HeadRepoID)
38 if err != nil || head == nil {
39 return ErrForkNotFound
40 }
41 forkDisk, err := s.DiskPath(head.OwnerUsername, head.Name)
42 if err != nil {
43 return err
44 }
45 tmpRef := fmt.Sprintf("refs/polar/tmp-merge-%d", pr.ID)
46 if _, err := git.MergeFromPath(ctx, baseDisk, forkDisk, pr.BaseBranch, pr.HeadBranch, tmpRef, msg, authorName, authorEmail); err != nil {
47 return err
48 }
49 } else {
50 if _, err := git.MergeBranches(ctx, baseDisk, pr.BaseBranch, pr.HeadBranch, msg, authorName, authorEmail); err != nil {
51 return err
52 }
53 }
54
55 if err := s.SetPullRequestStatus(ctx, pr.ID, "merged", &mergedByID); err != nil {
56 return err
57 }
58 s.TouchUpdatedAt(ctx, base.ID)
59 return nil
60 }
61