diff options
author | James Fargher <proglottis@gmail.com> | 2021-03-11 05:01:28 +0300 |
---|---|---|
committer | James Fargher <proglottis@gmail.com> | 2021-03-11 05:01:28 +0300 |
commit | fcdef3b1e8c4b431700a9c2e47db830d32a8ad6f (patch) | |
tree | 853ce74f9452c8051b4b474d3882a17272c1eaca | |
parent | 3822772ed121b764fdcc5011d199c37ef76e06a9 (diff) | |
parent | 68be9dfdb4bc56b80278f3e3fe8e9fc2fb3de418 (diff) |
Merge branch 'pks-operations-typing' into 'master'
operations: Convert several interfaces to use proper types
See merge request gitlab-org/gitaly!3239
20 files changed, 217 insertions, 125 deletions
diff --git a/cmd/gitaly-git2go/cherry_pick_test.go b/cmd/gitaly-git2go/cherry_pick_test.go index 9cad461b1..996f8f5a0 100644 --- a/cmd/gitaly-git2go/cherry_pick_test.go +++ b/cmd/gitaly-git2go/cherry_pick_test.go @@ -165,13 +165,13 @@ func TestCherryPick(t *testing.T) { } require.NoError(t, err) - assert.Equal(t, tc.expectedCommitID, response) + assert.Equal(t, tc.expectedCommitID, response.String()) repo, err := git.OpenRepository(repoPath) require.NoError(t, err) defer repo.Free() - commitOid, err := git.NewOid(response) + commitOid, err := git.NewOid(response.String()) require.NoError(t, err) commit, err := repo.LookupCommit(commitOid) diff --git a/cmd/gitaly-git2go/revert_test.go b/cmd/gitaly-git2go/revert_test.go index 211feabc0..b24d5785c 100644 --- a/cmd/gitaly-git2go/revert_test.go +++ b/cmd/gitaly-git2go/revert_test.go @@ -183,13 +183,13 @@ func TestRevert_trees(t *testing.T) { } require.NoError(t, err) - assert.Equal(t, tc.expectedCommitID, response) + assert.Equal(t, tc.expectedCommitID, response.String()) repo, err := git.OpenRepository(repoPath) require.NoError(t, err) defer repo.Free() - commitOid, err := git.NewOid(response) + commitOid, err := git.NewOid(response.String()) require.NoError(t, err) commit, err := repo.LookupCommit(commitOid) diff --git a/internal/git/localrepo/objects.go b/internal/git/localrepo/objects.go index 6d3c9a3bb..7d03eb4c5 100644 --- a/internal/git/localrepo/objects.go +++ b/internal/git/localrepo/objects.go @@ -132,7 +132,7 @@ func (repo *Repo) WriteTag( objectType string, tagName, userName, userEmail, tagBody []byte, committerDate time.Time, -) (string, error) { +) (git.ObjectID, error) { stdout := &bytes.Buffer{} stderr := &bytes.Buffer{} @@ -159,7 +159,12 @@ func (repo *Repo) WriteTag( return "", MktagError{tagName: tagName, stderr: stderr.String()} } - return text.ChompBytes(stdout.Bytes()), nil + tagID, err := git.NewObjectIDFromHex(text.ChompBytes(stdout.Bytes())) + if err != nil { + return "", fmt.Errorf("could not parse tag ID: %w", err) + } + + return tagID, nil } // InvalidObjectError is returned when trying to get an object id that is invalid or does not exist. diff --git a/internal/git/localrepo/objects_test.go b/internal/git/localrepo/objects_test.go index 91bbcb7c0..d2926835f 100644 --- a/internal/git/localrepo/objects_test.go +++ b/internal/git/localrepo/objects_test.go @@ -216,8 +216,8 @@ func TestRepo_WriteTag(t *testing.T) { tagObjID, err := repo.WriteTag(ctx, tc.objectID, tc.objectType, tc.tagName, tc.userName, tc.userEmail, tc.tagBody, tc.authorDate) require.NoError(t, err) - repoTagObjID := testhelper.MustRunCommand(t, nil, "git", "-C", repoPath, "rev-parse", tagObjID) - require.Equal(t, text.ChompBytes(repoTagObjID), tagObjID) + repoTagObjID := testhelper.MustRunCommand(t, nil, "git", "-C", repoPath, "rev-parse", tagObjID.String()) + require.Equal(t, text.ChompBytes(repoTagObjID), tagObjID.String()) }) } } diff --git a/internal/git2go/apply.go b/internal/git2go/apply.go index 447e92530..93c74925b 100644 --- a/internal/git2go/apply.go +++ b/internal/git2go/apply.go @@ -5,6 +5,8 @@ import ( "encoding/gob" "fmt" "io" + + "gitlab.com/gitlab-org/gitaly/internal/git" ) // ErrMergeConflict is returned when there is a merge conflict. @@ -70,7 +72,7 @@ func (iter *slicePatchIterator) Err() error { return nil } // Apply applies the provided patches and returns the OID of the commit with the patches // applied. -func (b Executor) Apply(ctx context.Context, params ApplyParams) (string, error) { +func (b Executor) Apply(ctx context.Context, params ApplyParams) (git.ObjectID, error) { reader, writer := io.Pipe() defer writer.Close() @@ -108,5 +110,14 @@ func (b Executor) Apply(ctx context.Context, params ApplyParams) (string, error) return "", fmt.Errorf("decode: %w", err) } - return result.CommitID, result.Error + if result.Error != nil { + return "", result.Error + } + + commitID, err := git.NewObjectIDFromHex(result.CommitID) + if err != nil { + return "", fmt.Errorf("could not parse commit ID: %w", err) + } + + return commitID, nil } diff --git a/internal/git2go/apply_test.go b/internal/git2go/apply_test.go index 6f303257c..ca140f395 100644 --- a/internal/git2go/apply_test.go +++ b/internal/git2go/apply_test.go @@ -60,7 +60,7 @@ func TestExecutor_Apply(t *testing.T) { Author: author, Committer: committer, Message: "commit with a", - Parent: parentCommitSHA, + Parent: parentCommitSHA.String(), Actions: []Action{UpdateFile{Path: "file", OID: oidA.String()}}, }) require.NoError(t, err) @@ -70,7 +70,7 @@ func TestExecutor_Apply(t *testing.T) { Author: author, Committer: committer, Message: "commit to b", - Parent: parentCommitSHA, + Parent: parentCommitSHA.String(), Actions: []Action{UpdateFile{Path: "file", OID: oidB.String()}}, }) require.NoError(t, err) @@ -80,7 +80,7 @@ func TestExecutor_Apply(t *testing.T) { Author: author, Committer: committer, Message: "commit a -> b", - Parent: updateToA, + Parent: updateToA.String(), Actions: []Action{UpdateFile{Path: "file", OID: oidB.String()}}, }) require.NoError(t, err) @@ -94,16 +94,16 @@ func TestExecutor_Apply(t *testing.T) { }) require.NoError(t, err) - diffBetween := func(t testing.TB, fromCommit, toCommit string) []byte { + diffBetween := func(t testing.TB, fromCommit, toCommit git.ObjectID) []byte { t.Helper() return testhelper.MustRunCommand(t, nil, - "git", "-C", repoPath, "format-patch", "--stdout", fromCommit+".."+toCommit) + "git", "-C", repoPath, "format-patch", "--stdout", fromCommit.String()+".."+toCommit.String()) } for _, tc := range []struct { desc string patches []Patch - parentCommit string + parentCommit git.ObjectID tree []gittest.TreeEntry error error }{ @@ -198,7 +198,7 @@ func TestExecutor_Apply(t *testing.T) { commitID, err := executor.Apply(ctx, ApplyParams{ Repository: repoPath, Committer: committer, - ParentCommit: parentCommitSHA, + ParentCommit: parentCommitSHA.String(), Patches: NewSlicePatchIterator(tc.patches), }) if tc.error != nil { @@ -212,7 +212,7 @@ func TestExecutor_Apply(t *testing.T) { Committer: committer, Message: tc.patches[len(tc.patches)-1].Message, }, getCommit(t, ctx, repo, commitID)) - gittest.RequireTree(t, config.Config.Git.BinPath, repoPath, commitID, tc.tree) + gittest.RequireTree(t, config.Config.Git.BinPath, repoPath, commitID.String(), tc.tree) }) } } diff --git a/internal/git2go/cherry_pick.go b/internal/git2go/cherry_pick.go index 71c7c6f06..fb5b9de4f 100644 --- a/internal/git2go/cherry_pick.go +++ b/internal/git2go/cherry_pick.go @@ -4,6 +4,7 @@ import ( "context" "time" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" ) @@ -28,6 +29,6 @@ type CherryPickCommand struct { } // Run performs a cherry pick via gitaly-git2go. -func (m CherryPickCommand) Run(ctx context.Context, cfg config.Cfg) (string, error) { +func (m CherryPickCommand) Run(ctx context.Context, cfg config.Cfg) (git.ObjectID, error) { return runWithGob(ctx, cfg, "cherry-pick", m) } diff --git a/internal/git2go/commit.go b/internal/git2go/commit.go index 558c82bd9..8f0f03256 100644 --- a/internal/git2go/commit.go +++ b/internal/git2go/commit.go @@ -5,6 +5,8 @@ import ( "context" "encoding/gob" "fmt" + + "gitlab.com/gitlab-org/gitaly/internal/git" ) // IndexError is an error that was produced by performing an invalid operation on the index. @@ -57,7 +59,7 @@ type CommitParams struct { // Commit builds a commit from the actions, writes it to the object database and // returns its object id. -func (b Executor) Commit(ctx context.Context, params CommitParams) (string, error) { +func (b Executor) Commit(ctx context.Context, params CommitParams) (git.ObjectID, error) { input := &bytes.Buffer{} if err := gob.NewEncoder(input).Encode(params); err != nil { return "", err @@ -73,5 +75,14 @@ func (b Executor) Commit(ctx context.Context, params CommitParams) (string, erro return "", err } - return result.CommitID, result.Error + if result.Error != nil { + return "", result.Error + } + + commitID, err := git.NewObjectIDFromHex(result.CommitID) + if err != nil { + return "", fmt.Errorf("could not parse commit ID: %w", err) + } + + return commitID, nil } diff --git a/internal/git2go/commit_test.go b/internal/git2go/commit_test.go index c4c8427f7..ea6ecc5c2 100644 --- a/internal/git2go/commit_test.go +++ b/internal/git2go/commit_test.go @@ -33,7 +33,7 @@ func testMain(m *testing.M) int { } type commit struct { - Parent string + Parent git.ObjectID Author Signature Committer Signature Message string @@ -464,7 +464,7 @@ func TestExecutor_Commit(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { author := NewSignature("Author Name", "author.email@example.com", time.Now()) committer := NewSignature("Committer Name", "committer.email@example.com", time.Now()) - var parentCommit string + var parentCommit git.ObjectID for i, step := range tc.steps { message := fmt.Sprintf("commit %d", i+1) commitID, err := executor.Commit(ctx, CommitParams{ @@ -472,7 +472,7 @@ func TestExecutor_Commit(t *testing.T) { Author: author, Committer: committer, Message: message, - Parent: parentCommit, + Parent: parentCommit.String(), Actions: step.actions, }) @@ -490,17 +490,17 @@ func TestExecutor_Commit(t *testing.T) { Message: message, }, getCommit(t, ctx, repo, commitID)) - gittest.RequireTree(t, config.Config.Git.BinPath, repoPath, commitID, step.treeEntries) + gittest.RequireTree(t, config.Config.Git.BinPath, repoPath, commitID.String(), step.treeEntries) parentCommit = commitID } }) } } -func getCommit(t testing.TB, ctx context.Context, repo *localrepo.Repo, oid string) commit { +func getCommit(t testing.TB, ctx context.Context, repo *localrepo.Repo, oid git.ObjectID) commit { t.Helper() - data, err := repo.ReadObject(ctx, git.ObjectID(oid)) + data, err := repo.ReadObject(ctx, oid) require.NoError(t, err) var commit commit @@ -518,7 +518,7 @@ func getCommit(t testing.TB, ctx context.Context, repo *localrepo.Repo, oid stri switch field { case "parent": require.Empty(t, commit.Parent, "multi parent parsing not implemented") - commit.Parent = value + commit.Parent = git.ObjectID(value) case "author": require.Empty(t, commit.Author, "commit contained multiple authors") commit.Author = unmarshalSignature(t, value) diff --git a/internal/git2go/gob.go b/internal/git2go/gob.go index 4e760b437..7c4ef0554 100644 --- a/internal/git2go/gob.go +++ b/internal/git2go/gob.go @@ -8,6 +8,7 @@ import ( "fmt" "reflect" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" ) @@ -86,7 +87,7 @@ func SerializableError(err error) error { // runWithGob runs the specified gitaly-git2go cmd with the request gob-encoded // as input and returns the commit ID as string or an error. -func runWithGob(ctx context.Context, cfg config.Cfg, cmd string, request interface{}) (string, error) { +func runWithGob(ctx context.Context, cfg config.Cfg, cmd string, request interface{}) (git.ObjectID, error) { input := &bytes.Buffer{} if err := gob.NewEncoder(input).Encode(request); err != nil { return "", fmt.Errorf("%s: %w", cmd, err) @@ -106,5 +107,10 @@ func runWithGob(ctx context.Context, cfg config.Cfg, cmd string, request interfa return "", fmt.Errorf("%s: %w", cmd, result.Error) } - return result.CommitID, nil + commitID, err := git.NewObjectIDFromHex(result.CommitID) + if err != nil { + return "", fmt.Errorf("could not parse commit ID: %w", err) + } + + return commitID, nil } diff --git a/internal/git2go/revert.go b/internal/git2go/revert.go index 8e7af30ba..7dd1d7420 100644 --- a/internal/git2go/revert.go +++ b/internal/git2go/revert.go @@ -4,6 +4,7 @@ import ( "context" "time" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" ) @@ -26,6 +27,6 @@ type RevertCommand struct { Mainline uint `json:"mainline"` } -func (r RevertCommand) Run(ctx context.Context, cfg config.Cfg) (string, error) { +func (r RevertCommand) Run(ctx context.Context, cfg config.Cfg) (git.ObjectID, error) { return runWithGob(ctx, cfg, "revert", r) } diff --git a/internal/gitaly/service/operations/branches.go b/internal/gitaly/service/operations/branches.go index d23dee21e..b94b7a2e8 100644 --- a/internal/gitaly/service/operations/branches.go +++ b/internal/gitaly/service/operations/branches.go @@ -3,7 +3,6 @@ package operations import ( "context" "errors" - "fmt" "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/git/localrepo" @@ -41,15 +40,20 @@ func (s *Server) UserCreateBranch(ctx context.Context, req *gitalypb.UserCreateB return nil, status.Errorf(codes.FailedPrecondition, "revspec '%s' not found", req.StartPoint) } - referenceName := fmt.Sprintf("refs/heads/%s", req.BranchName) - _, err = repo.GetReference(ctx, git.ReferenceName(referenceName)) + startPointOID, err := git.NewObjectIDFromHex(startPointCommit.Id) + if err != nil { + return nil, status.Errorf(codes.Internal, "could not parse start point commit ID: %v", err) + } + + referenceName := git.NewReferenceNameFromBranchName(string(req.BranchName)) + _, err = repo.GetReference(ctx, referenceName) if err == nil { return nil, status.Errorf(codes.FailedPrecondition, "Could not update %s. Please refresh and try again.", req.BranchName) } else if !errors.Is(err, git.ErrReferenceNotFound) { return nil, status.Error(codes.Internal, err.Error()) } - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, startPointCommit.Id, git.ZeroOID.String()); err != nil { + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, startPointOID, git.ZeroOID); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserCreateBranchResponse{ @@ -106,8 +110,19 @@ func (s *Server) userUpdateBranchGo(ctx context.Context, req *gitalypb.UserUpdat return nil, err } - referenceName := fmt.Sprintf("refs/heads/%s", req.BranchName) - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, string(req.Newrev), string(req.Oldrev)); err != nil { + newOID, err := git.NewObjectIDFromHex(string(req.Newrev)) + if err != nil { + return nil, status.Errorf(codes.Internal, "could not parse newrev: %v", err) + } + + oldOID, err := git.NewObjectIDFromHex(string(req.Oldrev)) + if err != nil { + return nil, status.Errorf(codes.Internal, "could not parse oldrev: %v", err) + } + + referenceName := git.NewReferenceNameFromBranchName(string(req.BranchName)) + + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, newOID, oldOID); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserUpdateBranchResponse{ @@ -153,14 +168,14 @@ func (s *Server) UserDeleteBranch(ctx context.Context, req *gitalypb.UserDeleteB return nil, status.Errorf(codes.InvalidArgument, "Bad Request (empty user)") } - referenceName := fmt.Sprintf("refs/heads/%s", req.BranchName) + referenceName := git.NewReferenceNameFromBranchName(string(req.BranchName)) - referenceValue, err := localrepo.New(s.gitCmdFactory, req.Repository, s.cfg).GetReference(ctx, git.ReferenceName(referenceName)) + referenceValue, err := localrepo.New(s.gitCmdFactory, req.Repository, s.cfg).ResolveRevision(ctx, referenceName.Revision()) if err != nil { return nil, status.Errorf(codes.FailedPrecondition, "branch not found: %s", req.BranchName) } - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, git.ZeroOID.String(), referenceValue.Target); err != nil { + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, git.ZeroOID, referenceValue); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserDeleteBranchResponse{ diff --git a/internal/gitaly/service/operations/cherry_pick.go b/internal/gitaly/service/operations/cherry_pick.go index ac0f9c74c..a38448c84 100644 --- a/internal/gitaly/service/operations/cherry_pick.go +++ b/internal/gitaly/service/operations/cherry_pick.go @@ -10,7 +10,6 @@ import ( "gitlab.com/gitlab-org/gitaly/internal/git2go" "gitlab.com/gitlab-org/gitaly/internal/gitaly/rubyserver" "gitlab.com/gitlab-org/gitaly/internal/helper" - "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -67,7 +66,7 @@ func (s *Server) userCherryPick(ctx context.Context, req *gitalypb.UserCherryPic AuthorMail: string(req.User.Email), Message: string(req.Message), Commit: req.Commit.Id, - Ours: startRevision, + Ours: startRevision.String(), Mainline: mainline, }.Run(ctx, s.cfg) if err != nil { @@ -84,10 +83,10 @@ func (s *Server) userCherryPick(ctx context.Context, req *gitalypb.UserCherryPic } } - branch := "refs/heads/" + text.ChompBytes(req.BranchName) + referenceName := git.NewReferenceNameFromBranchName(string(req.BranchName)) branchCreated := false - oldrev, err := localRepo.ResolveRevision(ctx, git.Revision(fmt.Sprintf("%s^{commit}", branch))) + oldrev, err := localRepo.ResolveRevision(ctx, referenceName.Revision()+"^{commit}") if errors.Is(err, git.ErrReferenceNotFound) { branchCreated = true oldrev = git.ZeroOID @@ -100,7 +99,7 @@ func (s *Server) userCherryPick(ctx context.Context, req *gitalypb.UserCherryPic } if !branchCreated { - ancestor, err := s.isAncestor(ctx, req.Repository, oldrev.String(), newrev) + ancestor, err := s.isAncestor(ctx, req.Repository, oldrev, newrev) if err != nil { return nil, err } @@ -111,7 +110,7 @@ func (s *Server) userCherryPick(ctx context.Context, req *gitalypb.UserCherryPic } } - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, branch, newrev, oldrev.String()); err != nil { + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, newrev, oldrev); err != nil { if errors.As(err, &preReceiveError{}) { return &gitalypb.UserCherryPickResponse{ PreReceiveError: err.Error(), @@ -123,7 +122,7 @@ func (s *Server) userCherryPick(ctx context.Context, req *gitalypb.UserCherryPic return &gitalypb.UserCherryPickResponse{ BranchUpdate: &gitalypb.OperationBranchUpdate{ - CommitId: newrev, + CommitId: newrev.String(), BranchCreated: branchCreated, RepoCreated: !repoHadBranches, }, diff --git a/internal/gitaly/service/operations/commit_files.go b/internal/gitaly/service/operations/commit_files.go index e01bcf3cd..ca21e0867 100644 --- a/internal/gitaly/service/operations/commit_files.go +++ b/internal/gitaly/service/operations/commit_files.go @@ -182,8 +182,8 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi localRepo := localrepo.New(s.gitCmdFactory, header.Repository, s.cfg) - targetBranchName := "refs/heads/" + string(header.BranchName) - targetBranchCommit, err := localRepo.ResolveRevision(ctx, git.Revision(targetBranchName+"^{commit}")) + targetBranchName := git.NewReferenceNameFromBranchName(string(header.BranchName)) + targetBranchCommit, err := localRepo.ResolveRevision(ctx, targetBranchName.Revision()+"^{commit}") if err != nil { if !errors.Is(err, git.ErrReferenceNotFound) { return fmt.Errorf("resolve target branch commit: %w", err) @@ -192,23 +192,28 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi // the branch is being created } - parentCommitOID := header.StartSha - if parentCommitOID == "" { + var parentCommitOID git.ObjectID + if header.StartSha == "" { parentCommitOID, err = s.resolveParentCommit( ctx, localRepo, remoteRepo, targetBranchName, - targetBranchCommit.String(), + targetBranchCommit, string(header.StartBranchName), ) if err != nil { return fmt.Errorf("resolve parent commit: %w", err) } + } else { + parentCommitOID, err = git.NewObjectIDFromHex(header.StartSha) + if err != nil { + return helper.ErrInvalidArgumentf("cannot resolve parent commit: %w", err) + } } - if parentCommitOID != targetBranchCommit.String() { - if err := s.fetchMissingCommit(ctx, header.Repository, remoteRepo, parentCommitOID); err != nil { + if parentCommitOID != targetBranchCommit { + if err := s.fetchMissingCommit(ctx, localRepo, remoteRepo, parentCommitOID); err != nil { return fmt.Errorf("fetch missing commit: %w", err) } } @@ -339,7 +344,7 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi Author: author, Committer: committer, Message: string(header.CommitMessage), - Parent: parentCommitOID, + Parent: parentCommitOID.String(), Actions: actions, }) if err != nil { @@ -353,9 +358,9 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi oldRevision := parentCommitOID if targetBranchCommit == "" { - oldRevision = git.ZeroOID.String() + oldRevision = git.ZeroOID } else if header.Force { - oldRevision = targetBranchCommit.String() + oldRevision = targetBranchCommit } if err := s.updateReferenceWithHooks(ctx, header.Repository, header.User, targetBranchName, commitID, oldRevision); err != nil { @@ -367,7 +372,7 @@ func (s *Server) userCommitFiles(ctx context.Context, header *gitalypb.UserCommi } return stream.SendAndClose(&gitalypb.UserCommitFilesResponse{BranchUpdate: &gitalypb.OperationBranchUpdate{ - CommitId: commitID, + CommitId: commitID.String(), RepoCreated: !hasBranches, BranchCreated: parentCommitOID == "", }}) @@ -378,7 +383,14 @@ func sameRepository(repoA, repoB *gitalypb.Repository) bool { repoA.GetRelativePath() == repoB.GetRelativePath() } -func (s *Server) resolveParentCommit(ctx context.Context, local git.Repository, remote *gitalypb.Repository, targetBranch, targetBranchCommit, startBranch string) (string, error) { +func (s *Server) resolveParentCommit( + ctx context.Context, + local git.Repository, + remote *gitalypb.Repository, + targetBranch git.ReferenceName, + targetBranchCommit git.ObjectID, + startBranch string, +) (git.ObjectID, error) { if remote == nil && startBranch == "" { return targetBranchCommit, nil } @@ -418,7 +430,7 @@ func (s *Server) resolveParentCommit(ctx context.Context, local git.Repository, branch := targetBranch if startBranch != "" { - branch = "refs/heads/" + startBranch + branch = git.NewReferenceNameFromBranchName(startBranch) } refish := branch + "^{commit}" @@ -427,16 +439,21 @@ func (s *Server) resolveParentCommit(ctx context.Context, local git.Repository, return "", fmt.Errorf("resolving refish %q in %T: %w", refish, repo, err) } - return commit.String(), nil + return commit, nil } -func (s *Server) fetchMissingCommit(ctx context.Context, local, remote *gitalypb.Repository, commitID string) error { - if _, err := localrepo.New(s.gitCmdFactory, local, s.cfg).ResolveRevision(ctx, git.Revision(commitID+"^{commit}")); err != nil { - if !errors.Is(err, git.ErrReferenceNotFound) || remote == nil { +func (s *Server) fetchMissingCommit( + ctx context.Context, + localRepo *localrepo.Repo, + remoteRepo *gitalypb.Repository, + commit git.ObjectID, +) error { + if _, err := localRepo.ResolveRevision(ctx, commit.Revision()+"^{commit}"); err != nil { + if !errors.Is(err, git.ErrReferenceNotFound) || remoteRepo == nil { return fmt.Errorf("lookup parent commit: %w", err) } - if err := s.fetchRemoteObject(ctx, local, remote, commitID); err != nil { + if err := s.fetchRemoteObject(ctx, localRepo, remoteRepo, commit); err != nil { return fmt.Errorf("fetch parent commit: %w", err) } } @@ -444,9 +461,14 @@ func (s *Server) fetchMissingCommit(ctx context.Context, local, remote *gitalypb return nil } -func (s *Server) fetchRemoteObject(ctx context.Context, local, remote *gitalypb.Repository, sha string) error { +func (s *Server) fetchRemoteObject( + ctx context.Context, + localRepo *localrepo.Repo, + remoteRepo *gitalypb.Repository, + oid git.ObjectID, +) error { env, err := gitalyssh.UploadPackEnv(ctx, s.cfg, &gitalypb.SSHUploadPackRequest{ - Repository: remote, + Repository: remoteRepo, GitConfigOptions: []string{"uploadpack.allowAnySHA1InWant=true"}, }) if err != nil { @@ -454,21 +476,15 @@ func (s *Server) fetchRemoteObject(ctx context.Context, local, remote *gitalypb. } stderr := &bytes.Buffer{} - cmd, err := s.gitCmdFactory.New(ctx, local, nil, - git.SubCmd{ - Name: "fetch", - Flags: []git.Option{git.Flag{Name: "--no-tags"}}, - Args: []string{"ssh://gitaly/internal.git", sha}, - }, + if err := localRepo.ExecAndWait(ctx, nil, git.SubCmd{ + Name: "fetch", + Flags: []git.Option{git.Flag{Name: "--no-tags"}}, + Args: []string{"ssh://gitaly/internal.git", oid.String()}, + }, git.WithEnv(env...), git.WithStderr(stderr), - git.WithRefTxHook(ctx, local, s.cfg), - ) - if err != nil { - return err - } - - if err := cmd.Wait(); err != nil { + git.WithRefTxHook(ctx, localRepo, s.cfg), + ); err != nil { return errorWithStderr(err, stderr) } diff --git a/internal/gitaly/service/operations/merge.go b/internal/gitaly/service/operations/merge.go index 74edf8229..db3e90f43 100644 --- a/internal/gitaly/service/operations/merge.go +++ b/internal/gitaly/service/operations/merge.go @@ -14,7 +14,6 @@ import ( "gitlab.com/gitlab-org/gitaly/internal/git/repository" "gitlab.com/gitlab-org/gitaly/internal/git2go" "gitlab.com/gitlab-org/gitaly/internal/helper" - "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" ) @@ -56,8 +55,9 @@ func (s *Server) UserMergeBranch(stream gitalypb.OperationService_UserMergeBranc return err } - branch := "refs/heads/" + text.ChompBytes(firstRequest.Branch) - revision, err := localrepo.New(s.gitCmdFactory, repo, s.cfg).ResolveRevision(ctx, git.Revision(branch)) + referenceName := git.NewReferenceNameFromBranchName(string(firstRequest.Branch)) + + revision, err := localrepo.New(s.gitCmdFactory, repo, s.cfg).ResolveRevision(ctx, referenceName.Revision()) if err != nil { return err } @@ -86,6 +86,11 @@ func (s *Server) UserMergeBranch(stream gitalypb.OperationService_UserMergeBranc return err } + mergeOID, err := git.NewObjectIDFromHex(merge.CommitID) + if err != nil { + return helper.ErrInternalf("could not parse merge ID: %w", err) + } + if err := stream.Send(&gitalypb.UserMergeBranchResponse{ CommitId: merge.CommitID, }); err != nil { @@ -100,7 +105,7 @@ func (s *Server) UserMergeBranch(stream gitalypb.OperationService_UserMergeBranc return helper.ErrPreconditionFailedf("merge aborted by client") } - if err := s.updateReferenceWithHooks(ctx, firstRequest.Repository, firstRequest.User, branch, merge.CommitID, revision.String()); err != nil { + if err := s.updateReferenceWithHooks(ctx, firstRequest.Repository, firstRequest.User, referenceName, mergeOID, revision); err != nil { var preReceiveError preReceiveError var updateRefError updateRefError @@ -152,13 +157,19 @@ func (s *Server) UserFFBranch(ctx context.Context, in *gitalypb.UserFFBranchRequ return nil, helper.ErrInvalidArgument(err) } - branch := fmt.Sprintf("refs/heads/%s", in.Branch) - revision, err := localrepo.New(s.gitCmdFactory, in.Repository, s.cfg).ResolveRevision(ctx, git.Revision(branch)) + referenceName := git.NewReferenceNameFromBranchName(string(in.Branch)) + + revision, err := localrepo.New(s.gitCmdFactory, in.Repository, s.cfg).ResolveRevision(ctx, referenceName.Revision()) if err != nil { return nil, helper.ErrInvalidArgument(err) } - ancestor, err := s.isAncestor(ctx, in.Repository, revision.String(), in.CommitId) + commitID, err := git.NewObjectIDFromHex(in.CommitId) + if err != nil { + return nil, helper.ErrInvalidArgumentf("cannot parse commit ID: %w", err) + } + + ancestor, err := s.isAncestor(ctx, in.Repository, revision, commitID) if err != nil { return nil, err } @@ -166,7 +177,7 @@ func (s *Server) UserFFBranch(ctx context.Context, in *gitalypb.UserFFBranchRequ return nil, helper.ErrPreconditionFailedf("not fast forward") } - if err := s.updateReferenceWithHooks(ctx, in.Repository, in.User, branch, in.CommitId, revision.String()); err != nil { + if err := s.updateReferenceWithHooks(ctx, in.Repository, in.User, referenceName, commitID, revision); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserFFBranchResponse{ @@ -296,11 +307,11 @@ func (s *Server) UserMergeToRef(ctx context.Context, request *gitalypb.UserMerge }, nil } -func (s *Server) isAncestor(ctx context.Context, repo repository.GitRepo, ancestor, descendant string) (bool, error) { +func (s *Server) isAncestor(ctx context.Context, repo repository.GitRepo, ancestor, descendant git.ObjectID) (bool, error) { cmd, err := s.gitCmdFactory.New(ctx, repo, nil, git.SubCmd{ Name: "merge-base", Flags: []git.Option{git.Flag{Name: "--is-ancestor"}}, - Args: []string{ancestor, descendant}, + Args: []string{ancestor.String(), descendant.String()}, }) if err != nil { return false, helper.ErrInternalf("isAncestor: %w", err) diff --git a/internal/gitaly/service/operations/revert.go b/internal/gitaly/service/operations/revert.go index bde78398e..8192e5363 100644 --- a/internal/gitaly/service/operations/revert.go +++ b/internal/gitaly/service/operations/revert.go @@ -60,7 +60,7 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest AuthorMail: string(req.User.Email), AuthorDate: authorDate, Message: string(req.Message), - Ours: startRevision, + Ours: startRevision.String(), Revert: req.Commit.Id, Mainline: mainline, }.Run(ctx, s.cfg) @@ -77,10 +77,10 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest } } - branch := fmt.Sprintf("refs/heads/%s", req.BranchName) + referenceName := git.NewReferenceNameFromBranchName(string(req.BranchName)) branchCreated := false - oldrev, err := localRepo.ResolveRevision(ctx, git.Revision(fmt.Sprintf("%s^{commit}", branch))) + oldrev, err := localRepo.ResolveRevision(ctx, referenceName.Revision()+"^{commit}") if errors.Is(err, git.ErrReferenceNotFound) { branchCreated = true oldrev = git.ZeroOID @@ -93,7 +93,7 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest } if !branchCreated { - ancestor, err := s.isAncestor(ctx, req.Repository, oldrev.String(), newrev) + ancestor, err := s.isAncestor(ctx, req.Repository, oldrev, newrev) if err != nil { return nil, err } @@ -104,7 +104,7 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest } } - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, branch, newrev, oldrev.String()); err != nil { + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, newrev, oldrev); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserRevertResponse{ @@ -117,7 +117,7 @@ func (s *Server) UserRevert(ctx context.Context, req *gitalypb.UserRevertRequest return &gitalypb.UserRevertResponse{ BranchUpdate: &gitalypb.OperationBranchUpdate{ - CommitId: newrev, + CommitId: newrev.String(), BranchCreated: branchCreated, RepoCreated: !repoHadBranches, }, @@ -145,7 +145,7 @@ type requestFetchingStartRevision interface { GetStartBranchName() []byte } -func (s *Server) fetchStartRevision(ctx context.Context, req requestFetchingStartRevision) (string, error) { +func (s *Server) fetchStartRevision(ctx context.Context, req requestFetchingStartRevision) (git.ObjectID, error) { startBranchName := req.GetStartBranchName() if len(startBranchName) == 0 { startBranchName = req.GetBranchName() @@ -166,17 +166,19 @@ func (s *Server) fetchStartRevision(ctx context.Context, req requestFetchingStar } if req.GetStartRepository() == nil { - return startRevision.String(), nil + return startRevision, nil } - _, err = localrepo.New(s.gitCmdFactory, req.GetRepository(), s.cfg).ResolveRevision(ctx, startRevision.Revision()+"^{commit}") + localRepo := localrepo.New(s.gitCmdFactory, req.GetRepository(), s.cfg) + + _, err = localRepo.ResolveRevision(ctx, startRevision.Revision()+"^{commit}") if errors.Is(err, git.ErrReferenceNotFound) { - if err := s.fetchRemoteObject(ctx, req.GetRepository(), req.GetStartRepository(), startRevision.String()); err != nil { + if err := s.fetchRemoteObject(ctx, localRepo, req.GetStartRepository(), startRevision); err != nil { return "", helper.ErrInternalf("fetch start: %w", err) } } else if err != nil { return "", helper.ErrInvalidArgumentf("resolve start: %w", err) } - return startRevision.String(), nil + return startRevision, nil } diff --git a/internal/gitaly/service/operations/submodules.go b/internal/gitaly/service/operations/submodules.go index b906e1fb4..f551626f4 100644 --- a/internal/gitaly/service/operations/submodules.go +++ b/internal/gitaly/service/operations/submodules.go @@ -89,7 +89,9 @@ func (s *Server) userUpdateSubmodule(ctx context.Context, req *gitalypb.UserUpda }, nil } - branchRef, err := repo.GetReference(ctx, git.NewReferenceNameFromBranchName(string(req.GetBranch()))) + referenceName := git.NewReferenceNameFromBranchName(string(req.GetBranch())) + + branchOID, err := repo.ResolveRevision(ctx, referenceName.Revision()) if err != nil { if errors.Is(err, git.ErrReferenceNotFound) { return nil, helper.ErrInvalidArgumentf("Cannot find branch") @@ -152,13 +154,18 @@ func (s *Server) userUpdateSubmodule(ctx context.Context, req *gitalypb.UserUpda return nil, fmt.Errorf("%s: submodule subcommand: %w", userUpdateSubmoduleName, err) } + commitID, err := git.NewObjectIDFromHex(result.CommitID) + if err != nil { + return nil, helper.ErrInvalidArgumentf("cannot parse commit ID: %w", err) + } + if err := s.updateReferenceWithHooks( ctx, req.GetRepository(), req.GetUser(), - branchRef.Name.String(), - result.CommitID, - branchRef.Target, + referenceName, + commitID, + branchOID, ); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { diff --git a/internal/gitaly/service/operations/tags.go b/internal/gitaly/service/operations/tags.go index cd9520bfb..4fc8aa907 100644 --- a/internal/gitaly/service/operations/tags.go +++ b/internal/gitaly/service/operations/tags.go @@ -28,13 +28,13 @@ func (s *Server) UserDeleteTag(ctx context.Context, req *gitalypb.UserDeleteTagR return nil, status.Errorf(codes.InvalidArgument, "empty user") } - referenceName := fmt.Sprintf("refs/tags/%s", req.TagName) - revision, err := localrepo.New(s.gitCmdFactory, req.Repository, s.cfg).GetReference(ctx, git.ReferenceName(referenceName)) + referenceName := git.ReferenceName(fmt.Sprintf("refs/tags/%s", req.TagName)) + revision, err := localrepo.New(s.gitCmdFactory, req.Repository, s.cfg).ResolveRevision(ctx, referenceName.Revision()) if err != nil { return nil, status.Errorf(codes.FailedPrecondition, "tag not found: %s", req.TagName) } - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, git.ZeroOID.String(), revision.Target); err != nil { + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, git.ZeroOID, revision); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserDeleteTagResponse{ @@ -141,7 +141,7 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR // At this point we'll either be pointing to an object we were // provided with, or creating a new tag object and pointing to // that. - refObjectID := targetObjectID.String() + refObjectID := targetObjectID var tagObject *gitalypb.Tag if makingTag { localRepo := localrepo.New(s.gitCmdFactory, repo, s.cfg) @@ -168,14 +168,14 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR return nil, status.Error(codes.Internal, err.Error()) } - createdTag, err := log.GetTagCatfile(ctx, catFile, git.Revision(tagObjectID), string(req.TagName), false, false) + createdTag, err := log.GetTagCatfile(ctx, catFile, tagObjectID.Revision(), string(req.TagName), false, false) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } tagObject = &gitalypb.Tag{ Name: req.TagName, - Id: tagObjectID, + Id: tagObjectID.String(), Message: createdTag.Message, MessageSize: createdTag.MessageSize, //TargetCommit: is filled in below if needed @@ -190,8 +190,8 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR } } - referenceName := fmt.Sprintf("refs/tags/%s", req.TagName) - if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, refObjectID, git.ZeroOID.String()); err != nil { + referenceName := git.ReferenceName(fmt.Sprintf("refs/tags/%s", req.TagName)) + if err := s.updateReferenceWithHooks(ctx, req.Repository, req.User, referenceName, refObjectID, git.ZeroOID); err != nil { var preReceiveError preReceiveError if errors.As(err, &preReceiveError) { return &gitalypb.UserCreateTagResponse{ @@ -201,7 +201,7 @@ func (s *Server) UserCreateTag(ctx context.Context, req *gitalypb.UserCreateTagR var updateRefError updateRefError if errors.As(err, &updateRefError) { - refNameOK, err := git.CheckRefFormat(ctx, s.gitCmdFactory, referenceName) + refNameOK, err := git.CheckRefFormat(ctx, s.gitCmdFactory, referenceName.String()) if refNameOK { // The tag might not actually exist, // perhaps update-ref died for some diff --git a/internal/gitaly/service/operations/update_with_hooks.go b/internal/gitaly/service/operations/update_with_hooks.go index e062c86a9..08e38733b 100644 --- a/internal/gitaly/service/operations/update_with_hooks.go +++ b/internal/gitaly/service/operations/update_with_hooks.go @@ -43,7 +43,13 @@ func hookErrorMessage(sout string, serr string, err error) string { return sout } -func (s *Server) updateReferenceWithHooks(ctx context.Context, repo *gitalypb.Repository, user *gitalypb.User, reference, newrev, oldrev string) error { +func (s *Server) updateReferenceWithHooks( + ctx context.Context, + repo *gitalypb.Repository, + user *gitalypb.User, + reference git.ReferenceName, + newrev, oldrev git.ObjectID, +) error { transaction, praefect, err := metadata.TransactionMetadataFromContext(ctx) if err != nil { return err @@ -61,10 +67,10 @@ func (s *Server) updateReferenceWithHooks(ctx context.Context, repo *gitalypb.Re if reference == "" { return helper.ErrInternalf("updateReferenceWithHooks: got no reference") } - if err := git.ValidateObjectID(oldrev); err != nil { + if err := git.ValidateObjectID(oldrev.String()); err != nil { return helper.ErrInternalf("updateReferenceWithHooks: got invalid old value: %w", err) } - if err := git.ValidateObjectID(newrev); err != nil { + if err := git.ValidateObjectID(newrev.String()); err != nil { return helper.ErrInternalf("updateReferenceWithHooks: got invalid new value: %w", err) } @@ -79,7 +85,7 @@ func (s *Server) updateReferenceWithHooks(ctx context.Context, repo *gitalypb.Re msg := hookErrorMessage(stdout.String(), stderr.String(), err) return preReceiveError{message: msg} } - if err := s.hookManager.UpdateHook(ctx, repo, reference, oldrev, newrev, env, &stdout, &stderr); err != nil { + if err := s.hookManager.UpdateHook(ctx, repo, reference.String(), oldrev.String(), newrev.String(), env, &stdout, &stderr); err != nil { msg := hookErrorMessage(stdout.String(), stderr.String(), err) return preReceiveError{message: msg} } @@ -103,12 +109,12 @@ func (s *Server) updateReferenceWithHooks(ctx context.Context, repo *gitalypb.Re return err } - if err := updater.Update(git.ReferenceName(reference), newrev, oldrev); err != nil { + if err := updater.Update(reference, newrev.String(), oldrev.String()); err != nil { return err } if err := updater.Wait(); err != nil { - return updateRefError{reference: reference} + return updateRefError{reference: reference.String()} } if err := s.hookManager.PostReceiveHook(ctx, repo, nil, env, strings.NewReader(changes), &stdout, &stderr); err != nil { diff --git a/internal/gitaly/service/operations/update_with_hooks_test.go b/internal/gitaly/service/operations/update_with_hooks_test.go index 5f79dd64a..557b8dffc 100644 --- a/internal/gitaly/service/operations/update_with_hooks_test.go +++ b/internal/gitaly/service/operations/update_with_hooks_test.go @@ -56,7 +56,7 @@ func TestUpdateReferenceWithHooks_invalidParameters(t *testing.T) { Email: []byte("mail@example.com"), } - revA, revB := strings.Repeat("a", 40), strings.Repeat("b", 40) + revA, revB := git.ObjectID(strings.Repeat("a", 40)), git.ObjectID(strings.Repeat("b", 40)) server := NewServer(config.Config, nil, &mockHookManager{}, nil, nil, nil) @@ -64,9 +64,10 @@ func TestUpdateReferenceWithHooks_invalidParameters(t *testing.T) { defer cancel() testCases := []struct { - desc string - ref, newRev, oldRev string - expectedErr string + desc string + ref git.ReferenceName + newRev, oldRev git.ObjectID + expectedErr string }{ { desc: "missing reference", @@ -269,7 +270,7 @@ func TestUpdateReferenceWithHooks(t *testing.T) { hookServer := NewServer(config.Config, nil, hookManager, nil, nil, gitCmdFactory) - err := hookServer.updateReferenceWithHooks(ctx, repo, user, "refs/heads/master", git.ZeroOID.String(), oldRev) + err := hookServer.updateReferenceWithHooks(ctx, repo, user, git.ReferenceName("refs/heads/master"), git.ZeroOID, git.ObjectID(oldRev)) if tc.expectedErr == "" { require.NoError(t, err) } else { |