1package git2go
2
3import (
4	"context"
5	"errors"
6	"fmt"
7	"io"
8	"time"
9
10	"gitlab.com/gitlab-org/gitaly/v14/internal/git/repository"
11)
12
13const (
14	// MergeRecursionLimit limits how many virtual merge bases are computed
15	// in a recursive merge.
16	MergeRecursionLimit = 20
17)
18
19// MergeCommand contains parameters to perform a merge.
20type MergeCommand struct {
21	// Repository is the path to execute merge in.
22	Repository string `json:"repository"`
23	// AuthorName is the author name of merge commit.
24	AuthorName string `json:"author_name"`
25	// AuthorMail is the author mail of merge commit.
26	AuthorMail string `json:"author_mail"`
27	// AuthorDate is the auithor date of merge commit.
28	AuthorDate time.Time `json:"author_date"`
29	// Message is the message to be used for the merge commit.
30	Message string `json:"message"`
31	// Ours is the commit that is to be merged into theirs.
32	Ours string `json:"ours"`
33	// Theirs is the commit into which ours is to be merged.
34	Theirs string `json:"theirs"`
35	// AllowConflicts controls whether conflicts are allowed. If they are,
36	// then conflicts will be committed as part of the result.
37	AllowConflicts bool `json:"allow_conflicts"`
38}
39
40// MergeResult contains results from a merge.
41type MergeResult struct {
42	// CommitID is the object ID of the generated merge commit.
43	CommitID string `json:"commit_id"`
44}
45
46// MergeCommandFromSerialized deserializes the merge request from its JSON representation encoded with base64.
47func MergeCommandFromSerialized(serialized string) (MergeCommand, error) {
48	var request MergeCommand
49	if err := deserialize(serialized, &request); err != nil {
50		return MergeCommand{}, err
51	}
52
53	if err := request.verify(); err != nil {
54		return MergeCommand{}, fmt.Errorf("merge: %w: %s", ErrInvalidArgument, err.Error())
55	}
56
57	return request, nil
58}
59
60// SerializeTo serializes the merge result and writes it into the writer.
61func (m MergeResult) SerializeTo(w io.Writer) error {
62	return serializeTo(w, m)
63}
64
65// Merge performs a merge via gitaly-git2go.
66func (b Executor) Merge(ctx context.Context, repo repository.GitRepo, m MergeCommand) (MergeResult, error) {
67	if err := m.verify(); err != nil {
68		return MergeResult{}, fmt.Errorf("merge: %w: %s", ErrInvalidArgument, err.Error())
69	}
70
71	commitID, err := b.runWithGob(ctx, repo, "merge", m)
72	if err != nil {
73		return MergeResult{}, err
74	}
75
76	return MergeResult{
77		CommitID: commitID.String(),
78	}, nil
79}
80
81func (m MergeCommand) verify() error {
82	if m.Repository == "" {
83		return errors.New("missing repository")
84	}
85	if m.AuthorName == "" {
86		return errors.New("missing author name")
87	}
88	if m.AuthorMail == "" {
89		return errors.New("missing author mail")
90	}
91	if m.Message == "" {
92		return errors.New("missing message")
93	}
94	if m.Ours == "" {
95		return errors.New("missing ours")
96	}
97	if m.Theirs == "" {
98		return errors.New("missing theirs")
99	}
100	return nil
101}
102