Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2020-09-21 14:14:35 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2020-09-22 11:14:26 +0300
commitfe8b701dac4a47ff490e7c3742cf1cf1a898febe (patch)
treee066880b978e39af28fd5508d020c65021486025 /internal/gitaly/service/operations/merge.go
parent542161b021db9c7304edc446b153c8d7478f237b (diff)
operations: Implement UserMergeToRef
This commit ports the operations.UserMergeToRef RPC from Ruby to Go. The Go implementation is as-of now hidden behind a new feature flag "gitaly_go_user_merge_to_ref".
Diffstat (limited to 'internal/gitaly/service/operations/merge.go')
-rw-r--r--internal/gitaly/service/operations/merge.go66
1 files changed, 66 insertions, 0 deletions
diff --git a/internal/gitaly/service/operations/merge.go b/internal/gitaly/service/operations/merge.go
index 2a19c9171..c6a94f3c1 100644
--- a/internal/gitaly/service/operations/merge.go
+++ b/internal/gitaly/service/operations/merge.go
@@ -318,11 +318,77 @@ func validateUserMergeToRefRequest(in *gitalypb.UserMergeToRefRequest) error {
return nil
}
+// userMergeToRef overwrites the given TargetRef to point to either Branch or
+// FirstParentRef. Afterwards, it performs a merge of SourceSHA with either
+// Branch or FirstParentRef and updates TargetRef to the merge commit.
+func (s *server) userMergeToRef(ctx context.Context, request *gitalypb.UserMergeToRefRequest) (*gitalypb.UserMergeToRefResponse, error) {
+ repoPath, err := s.locator.GetPath(request.Repository)
+ if err != nil {
+ return nil, err
+ }
+
+ repo := git.NewRepository(request.Repository)
+
+ refName := string(request.Branch)
+ if request.FirstParentRef != nil {
+ refName = string(request.FirstParentRef)
+ }
+
+ ref, err := repo.ResolveRefish(ctx, refName)
+ if err != nil {
+ //nolint:stylecheck
+ return nil, helper.ErrInvalidArgument(errors.New("Invalid merge source"))
+ }
+
+ sourceRef, err := repo.ResolveRefish(ctx, request.SourceSha)
+ if err != nil {
+ //nolint:stylecheck
+ return nil, helper.ErrInvalidArgument(errors.New("Invalid merge source"))
+ }
+
+ // First, overwrite the reference with the target reference.
+ if err := repo.UpdateRef(ctx, string(request.TargetRef), ref, ""); err != nil {
+ return nil, updateRefError{reference: string(request.TargetRef)}
+ }
+
+ // Now, we create the merge commit...
+ merge, err := git2go.MergeCommand{
+ Repository: repoPath,
+ AuthorName: string(request.User.Name),
+ AuthorMail: string(request.User.Email),
+ Message: string(request.Message),
+ Ours: ref,
+ Theirs: sourceRef,
+ }.Run(ctx, s.cfg)
+ if err != nil {
+ if errors.Is(err, git2go.ErrInvalidArgument) {
+ return nil, helper.ErrInvalidArgument(err)
+ }
+ //nolint:stylecheck
+ return nil, fmt.Errorf("Failed to create merge commit for source_sha %s and target_sha %s at %s", sourceRef, string(request.TargetRef), refName)
+ }
+
+ // ... and move branch from target ref to the merge commit. The Ruby
+ // implementation doesn't invoke hooks, so we don't either.
+ if err := repo.UpdateRef(ctx, string(request.TargetRef), merge.CommitID, ref); err != nil {
+ //nolint:stylecheck
+ return nil, helper.ErrPreconditionFailed(fmt.Errorf("Could not update %s. Please refresh and try again", string(request.TargetRef)))
+ }
+
+ return &gitalypb.UserMergeToRefResponse{
+ CommitId: merge.CommitID,
+ }, nil
+}
+
func (s *server) UserMergeToRef(ctx context.Context, in *gitalypb.UserMergeToRefRequest) (*gitalypb.UserMergeToRefResponse, error) {
if err := validateUserMergeToRefRequest(in); err != nil {
return nil, helper.ErrInvalidArgument(err)
}
+ if featureflag.IsEnabled(ctx, featureflag.GoUserMergeBranch) {
+ return s.userMergeToRef(ctx, in)
+ }
+
client, err := s.ruby.OperationServiceClient(ctx)
if err != nil {
return nil, helper.ErrInternal(err)