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:
authorPaul Okstad <pokstad@gitlab.com>2020-10-17 00:18:57 +0300
committerPaul Okstad <pokstad@gitlab.com>2020-10-21 09:21:12 +0300
commita3b2b64e6de53d5cdb9a4f51c6bff2c349479f53 (patch)
treee70ee1d0abec0b93761fd87d745912c1df7c7d19
parentd93c0385c47b69e351b8dd3c0ea00c68b5d48e21 (diff)
-rw-r--r--cmd/gitaly-git2go/resolve_conflicts.go27
-rw-r--r--go.mod1
-rw-r--r--go.sum1
-rw-r--r--internal/git2go/resolve_conflicts.go4
-rw-r--r--internal/gitaly/service/conflicts/resolve_conflicts.go157
5 files changed, 157 insertions, 33 deletions
diff --git a/cmd/gitaly-git2go/resolve_conflicts.go b/cmd/gitaly-git2go/resolve_conflicts.go
index 3c8bf6eed..ba1d516cb 100644
--- a/cmd/gitaly-git2go/resolve_conflicts.go
+++ b/cmd/gitaly-git2go/resolve_conflicts.go
@@ -7,6 +7,7 @@ import (
"errors"
"flag"
"fmt"
+ "os"
"strings"
"time"
@@ -149,6 +150,32 @@ func (cmd resolveSubcommand) Run() error {
)
}
+ tree, err := index.WriteTreeTo(repo)
+ if err != nil {
+ return err
+ }
+
+ committer := git.Signature{
+ Name: sanitizeSignatureInfo(request.AuthorName),
+ Email: sanitizeSignatureInfo(request.AuthorMail),
+ When: request.AuthorDate,
+ }
+
+ commit, err := repo.CreateCommitFromIds("", &committer, &committer, request.Message, tree, ours.Id(), theirs.Id())
+ if err != nil {
+ return fmt.Errorf("could not create resolve conflict commit: %w", err)
+ }
+
+ response := git2go.ResolveResult{
+ git2go.MergeResult{
+ CommitID: commit.String(),
+ },
+ }
+
+ if err := response.SerializeTo(os.Stdout); err != nil {
+ return err
+ }
+
return nil
}
diff --git a/go.mod b/go.mod
index a862936d6..a0bda0dfb 100644
--- a/go.mod
+++ b/go.mod
@@ -34,6 +34,7 @@ require (
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff
golang.org/x/text v0.3.3 // indirect
google.golang.org/grpc v1.24.0
+ gopkg.in/errgo.v2 v2.1.0
gopkg.in/yaml.v2 v2.3.0
)
diff --git a/go.sum b/go.sum
index d1071f462..25b882e1b 100644
--- a/go.sum
+++ b/go.sum
@@ -605,6 +605,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
diff --git a/internal/git2go/resolve_conflicts.go b/internal/git2go/resolve_conflicts.go
index 5eb2535b2..bc1057526 100644
--- a/internal/git2go/resolve_conflicts.go
+++ b/internal/git2go/resolve_conflicts.go
@@ -13,7 +13,9 @@ type ResolveCommand struct {
Resolutions []conflict.Resolution `json:"conflict_files"`
}
-type ResolveResult struct{}
+type ResolveResult struct {
+ MergeResult `json:"merge_result"`
+}
func ResolveCommandFromSerialized(serialized string) (ResolveCommand, error) {
var request ResolveCommand
diff --git a/internal/gitaly/service/conflicts/resolve_conflicts.go b/internal/gitaly/service/conflicts/resolve_conflicts.go
index 9b283f475..5f6aa3eee 100644
--- a/internal/gitaly/service/conflicts/resolve_conflicts.go
+++ b/internal/gitaly/service/conflicts/resolve_conflicts.go
@@ -2,19 +2,24 @@ package conflicts
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
"io"
+ "sort"
"gitlab.com/gitlab-org/gitaly/client"
"gitlab.com/gitlab-org/gitaly/internal/git"
- "gitlab.com/gitlab-org/gitaly/internal/git/repository"
- "gitlab.com/gitlab-org/gitaly/internal/gitaly/config"
+ "gitlab.com/gitlab-org/gitaly/internal/git/conflict"
+ "gitlab.com/gitlab-org/gitaly/internal/git2go"
"gitlab.com/gitlab-org/gitaly/internal/gitaly/rubyserver"
+ "gitlab.com/gitlab-org/gitaly/internal/gitalyssh"
+ "gitlab.com/gitlab-org/gitaly/internal/helper"
"gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag"
"gitlab.com/gitlab-org/gitaly/proto/go/gitalypb"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
+ "gopkg.in/errgo.v2/errors"
)
func (s *server) ResolveConflicts(stream gitalypb.ConflictsService_ResolveConflictsServer) error {
@@ -102,21 +107,6 @@ func validateResolveConflictsHeader(header *gitalypb.ResolveConflictsRequestHead
return nil
}
-type conflictFile struct {
- OldPath string `json:"old_path"`
- NewPath string `json:"new_path"`
- Sections map[string]string `json:"sections"`
-}
-
-func cfgContainsRepo(cfg config.Cfg, r repository.GitRepo) bool {
- for _, s := range cfg.Storages {
- if r.GetStorageName() == s.Name {
- return true
- }
- }
- return false
-}
-
func (s *server) resolveConflicts(header *gitalypb.ResolveConflictsRequestHeader, stream gitalypb.ConflictsService_ResolveConflictsServer) error {
b := bytes.NewBuffer(nil)
for {
@@ -135,31 +125,134 @@ func (s *server) resolveConflicts(header *gitalypb.ResolveConflictsRequestHeader
}
}
- var conflicts []map[string]conflictFile
- if err := json.NewDecoder(b).Decode(&conflicts); err != nil {
+ var resolutions []conflict.Resolution
+ if err := json.NewDecoder(b).Decode(&resolutions); err != nil {
+ return err
+ }
+
+ if err := s.repoWithBranchCommit(
+ stream.Context(),
+ header.GetRepository(),
+ header.GetTargetRepository(),
+ header.SourceBranch,
+ header.TargetBranch,
+ ); err != nil {
return err
}
- srcRepo := git.NewRepository(header.GetRepository())
+ repoPath, err := s.locator.GetRepoPath(header.GetRepository())
+ if err != nil {
+ return err
+ }
- var dstRepo git.Repository
- switch dst := header.GetTargetRepository(); {
- case dst == nil:
- dstRepo = srcRepo
- case cfgContainsRepo(s.cfg, dst):
- dstRepo = git.NewRepository(dst)
- default:
- var err error
- dstRepo, err = git.NewRemoteRepository(stream.Context(), dst, client.NewPool())
- if err != nil {
- return err
+ _, err = git2go.ResolveCommand{
+ MergeCommand: git2go.MergeCommand{
+ Repository: repoPath,
+ AuthorName: string(header.User.Name),
+ AuthorMail: string(header.User.Email),
+ Message: string(header.CommitMessage),
+ Ours: header.GetOurCommitOid(),
+ Theirs: header.GetTheirCommitOid(),
+ },
+ Resolutions: resolutions,
+ }.Run(stream.Context(), s.cfg)
+ if err != nil {
+ if errors.Is(git2go.ErrInvalidArgument)(err) {
+ return helper.ErrInvalidArgument(err)
+ }
+ return err
+ }
+
+ return stream.SendAndClose(&gitalypb.ResolveConflictsResponse{
+ ResolutionError: err.Error(),
+ })
+}
+
+func sameRepo(left, right *gitalypb.Repository) bool {
+ lgaod := left.GetGitAlternateObjectDirectories()
+ rgaod := right.GetGitAlternateObjectDirectories()
+ if len(lgaod) != len(rgaod) {
+ return false
+ }
+ sort.Strings(lgaod)
+ sort.Strings(rgaod)
+ for i := 0; i < len(lgaod); i++ {
+ if lgaod[i] != rgaod[i] {
+ return false
}
}
+ if left.GetGitObjectDirectory() != right.GetGitObjectDirectory() {
+ return false
+ }
+ if left.GetRelativePath() != right.GetRelativePath() {
+ return false
+ }
+ if left.GetStorageName() != right.GetStorageName() {
+ return false
+ }
+ return true
+}
+
+const gitalyInternalURL = "ssh://gitaly/internal.git"
+
+// repoWithCommit ensures that the source repo contains the same commit we
+// hope to merge with from the target branch, else it will be fetched from the
+// target repo. This is necessary since all merge/resolve logic occurs on the
+// same filesystem
+func (s *server) repoWithBranchCommit(ctx context.Context, srcRepo, targetRepo *gitalypb.Repository, srcBranch, targetBranch []byte) error {
+ src := git.NewRepository(srcRepo)
+ if sameRepo(srcRepo, targetRepo) {
+ _, err := src.ResolveRefish(ctx, string(targetBranch))
+ return err
+ }
+
+ target, err := git.NewRemoteRepository(ctx, targetRepo, client.NewPool())
+ if err != nil {
+ return err
+ }
+
+ oid, err := target.ResolveRefish(ctx, string(targetBranch))
+ if err != nil {
+ return err
+ }
+
+ ok, err := src.ContainsRef(ctx, oid)
+ if err != nil {
+ return err
+ }
+ if ok {
+ // target branch commit already exists in source repo; nothing
+ // to do
+ return err
+ }
+
+ env, err := gitalyssh.UploadPackEnv(ctx, &gitalypb.SSHUploadPackRequest{Repository: targetRepo})
+ if err != nil {
+ return err
+ }
+ // to enable fetching a specific SHA:
+ env = append(env, "uploadpack.allowAnySHA1InWant=true")
- targetOID, err := dstRepo.ResolveRefish(ctx, string(header.TargetBranch))
+ srcRepoPath, err := s.locator.GetRepoPath(srcRepo)
if err != nil {
return err
}
+ cmd, err := git.SafeBareCmd(ctx, git.CmdStream{}, env,
+ []git.Option{git.ValueFlag{"--git-dir", srcRepoPath}},
+ git.SubCmd{
+ Name: "fetch",
+ Flags: []git.Option{git.Flag{Name: "--no-tags"}},
+ Args: []string{gitalyInternalURL, oid},
+ },
+ )
+ if err != nil {
+ return err
+ }
+
+ if err := cmd.Wait(); err != nil {
+ return err
+ }
+
return nil
}