diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2021-09-13 09:14:43 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2021-09-13 09:14:43 +0300 |
commit | ffaf216dd0c5cbdc385b43f43d8cfec491fffb72 (patch) | |
tree | 248ca9f1c5575bf8cdf2c35e0408f7c638e36978 | |
parent | 229ba800d77e9a2baed1ee8fcd937ac0b094c3e0 (diff) | |
parent | a17188c3e567bfa60aeff87178f5effc21ad1438 (diff) |
Merge branch 'extract_default_branch' into 'master'
Implement GetDefaultBranch in localrepo
See merge request gitlab-org/gitaly!3817
-rw-r--r-- | internal/git/localrepo/refs.go | 40 | ||||
-rw-r--r-- | internal/git/localrepo/refs_test.go | 82 | ||||
-rw-r--r-- | internal/git/repository.go | 7 | ||||
-rw-r--r-- | internal/gitaly/service/commit/commits_by_message.go | 5 | ||||
-rw-r--r-- | internal/gitaly/service/commit/find_all_commits.go | 1 | ||||
-rw-r--r-- | internal/gitaly/service/commit/find_all_commits_test.go | 1 | ||||
-rw-r--r-- | internal/gitaly/service/commit/find_commits.go | 4 | ||||
-rw-r--r-- | internal/gitaly/service/commit/languages.go | 5 | ||||
-rw-r--r-- | internal/gitaly/service/commit/list_files.go | 13 | ||||
-rw-r--r-- | internal/gitaly/service/commit/list_files_test.go | 12 | ||||
-rw-r--r-- | internal/gitaly/service/commit/server.go | 3 | ||||
-rw-r--r-- | internal/gitaly/service/operations/apply_patch.go | 9 | ||||
-rw-r--r-- | internal/gitaly/service/operations/apply_patch_test.go | 7 | ||||
-rw-r--r-- | internal/gitaly/service/ref/refs.go | 103 | ||||
-rw-r--r-- | internal/gitaly/service/ref/refs_test.go | 117 | ||||
-rw-r--r-- | internal/gitaly/service/remote/fetch_internal_remote.go | 7 | ||||
-rw-r--r-- | internal/gitaly/service/remote/update_remote_mirror.go | 7 |
17 files changed, 172 insertions, 251 deletions
diff --git a/internal/git/localrepo/refs.go b/internal/git/localrepo/refs.go index ac9c69fd1..264bee4d2 100644 --- a/internal/git/localrepo/refs.go +++ b/internal/git/localrepo/refs.go @@ -266,3 +266,43 @@ func (repo *Repo) GetRemoteReferences(ctx context.Context, remote string, opts . return refs, nil } + +// GetDefaultBranch determines the default branch name +func (repo *Repo) GetDefaultBranch(ctx context.Context) (git.ReferenceName, error) { + var stdout bytes.Buffer + err := repo.ExecAndWait(ctx, + git.SubCmd{ + Name: "rev-parse", + Flags: []git.Option{git.Flag{Name: "--symbolic-full-name"}}, + Args: []string{"HEAD"}, + }, + git.WithStdout(&stdout), + ) + headRef := strings.TrimSpace(stdout.String()) + if err != nil { + // If the ref pointed at by HEAD doesn't exist, the rev-parse fails + // returning the string `"HEAD"` + if headRef == "HEAD" { + ok, err := repo.HasRevision(ctx, git.DefaultRef.Revision()) + if err != nil { + return "", err + } + if ok { + return git.DefaultRef, nil + } + + ok, err = repo.HasRevision(ctx, git.LegacyDefaultRef.Revision()) + if err != nil { + return "", err + } + if ok { + return git.LegacyDefaultRef, nil + } + + return "", git.ErrNoDefaultBranch + } + return "", err + } + + return git.ReferenceName(headRef), nil +} diff --git a/internal/git/localrepo/refs_test.go b/internal/git/localrepo/refs_test.go index a99384e42..652df1a80 100644 --- a/internal/git/localrepo/refs_test.go +++ b/internal/git/localrepo/refs_test.go @@ -454,3 +454,85 @@ func TestRepo_UpdateRef(t *testing.T) { }) } } + +func TestGetDefaultBranch(t *testing.T) { + const testOID = "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863" + + for _, tc := range []struct { + desc string + repo func(t *testing.T) *Repo + expectedName git.ReferenceName + expectedErr error + }{ + { + desc: "default ref", + repo: func(t *testing.T) *Repo { + repo, repoPath := setupRepo(t, true) + oid := gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(), gittest.WithBranch("apple")) + gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(oid), gittest.WithBranch("main")) + return repo + }, + expectedName: git.DefaultRef, + }, + { + desc: "legacy default ref", + repo: func(t *testing.T) *Repo { + repo, repoPath := setupRepo(t, true) + oid := gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(), gittest.WithBranch("apple")) + gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(oid), gittest.WithBranch("master")) + return repo + }, + expectedName: git.LegacyDefaultRef, + }, + { + desc: "no branches", + repo: func(t *testing.T) *Repo { + repo, _ := setupRepo(t, true) + return repo + }, + expectedErr: git.ErrNoDefaultBranch, + }, + { + desc: "no default branches", + repo: func(t *testing.T) *Repo { + repo, repoPath := setupRepo(t, true) + oid := gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(), gittest.WithBranch("apple")) + gittest.WriteCommit(t, repo.cfg, repoPath, gittest.WithParents(oid), gittest.WithBranch("banana")) + return repo + }, + expectedErr: git.ErrNoDefaultBranch, + }, + { + desc: "test repo default", + repo: func(t *testing.T) *Repo { + repo, _ := setupRepo(t, false) + return repo + }, + expectedName: git.LegacyDefaultRef, + }, + { + desc: "test repo HEAD set", + repo: func(t *testing.T) *Repo { + repo, repoPath := setupRepo(t, false) + gittest.Exec(t, repo.cfg, "-C", repoPath, "update-ref", "refs/heads/feature", testOID) + gittest.Exec(t, repo.cfg, "-C", repoPath, "symbolic-ref", "HEAD", "refs/heads/feature") + return repo + }, + expectedName: git.NewReferenceNameFromBranchName("feature"), + }, + } { + t.Run(tc.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + name, err := tc.repo(t).GetDefaultBranch(ctx) + if tc.expectedErr != nil { + require.Equal(t, tc.expectedErr, err) + return + } + + require.NoError(t, err) + require.Equal(t, tc.expectedName, name) + }) + } +} diff --git a/internal/git/repository.go b/internal/git/repository.go index e5f5b25d5..3ebe6cec4 100644 --- a/internal/git/repository.go +++ b/internal/git/repository.go @@ -13,12 +13,12 @@ const DefaultBranch = "main" // DefaultRef is the reference that GitLab will use if HEAD of the bare repository // is not found, or other edge cases to detect the default branch. -var DefaultRef = []byte("refs/heads/" + DefaultBranch) +const DefaultRef = ReferenceName("refs/heads/" + DefaultBranch) // LegacyDefaultRef is the reference that used to be the default HEAD of the bare // repository. If the default reference is not found, Gitaly will still test the // legacy default. -var LegacyDefaultRef = []byte("refs/heads/master") +const LegacyDefaultRef = ReferenceName("refs/heads/master") var ( // ErrReferenceNotFound represents an error when a reference was not @@ -32,6 +32,9 @@ var ( ErrAlreadyExists = errors.New("already exists") // ErrNotFound represents an error when the resource can't be found. ErrNotFound = errors.New("not found") + // ErrNoDefaultBranch represents an error when the repository has no + // default branch + ErrNoDefaultBranch = errors.New("no default branch") ) // Repository is the common interface of different repository implementations. diff --git a/internal/gitaly/service/commit/commits_by_message.go b/internal/gitaly/service/commit/commits_by_message.go index 63a8898c9..6353cf0ee 100644 --- a/internal/gitaly/service/commit/commits_by_message.go +++ b/internal/gitaly/service/commit/commits_by_message.go @@ -53,12 +53,11 @@ func (s *server) commitsByMessage(in *gitalypb.CommitsByMessageRequest, stream g revision := in.GetRevision() if len(revision) == 0 { - var err error - - revision, err = defaultBranchName(ctx, repo) + defaultBranch, err := repo.GetDefaultBranch(ctx) if err != nil { return err } + revision = []byte(defaultBranch) } var paths []string diff --git a/internal/gitaly/service/commit/find_all_commits.go b/internal/gitaly/service/commit/find_all_commits.go index 796c7185b..26d13e8dc 100644 --- a/internal/gitaly/service/commit/find_all_commits.go +++ b/internal/gitaly/service/commit/find_all_commits.go @@ -10,6 +10,7 @@ import ( ) // We declare this function in variables so that we can override them in our tests +//nolint:staticcheck // FindBranchNames is deprecated but the tests are difficult to refactor var _findBranchNamesFunc = ref.FindBranchNames func (s *server) FindAllCommits(in *gitalypb.FindAllCommitsRequest, stream gitalypb.CommitService_FindAllCommitsServer) error { diff --git a/internal/gitaly/service/commit/find_all_commits_test.go b/internal/gitaly/service/commit/find_all_commits_test.go index ba7b7ff06..893b33af8 100644 --- a/internal/gitaly/service/commit/find_all_commits_test.go +++ b/internal/gitaly/service/commit/find_all_commits_test.go @@ -16,6 +16,7 @@ import ( func TestSuccessfulFindAllCommitsRequest(t *testing.T) { defer func() { + //nolint:staticcheck // FindBranchNames is deprecated but the tests are difficult to refactor _findBranchNamesFunc = ref.FindBranchNames }() diff --git a/internal/gitaly/service/commit/find_commits.go b/internal/gitaly/service/commit/find_commits.go index 6367aa35d..6f6f63b4d 100644 --- a/internal/gitaly/service/commit/find_commits.go +++ b/internal/gitaly/service/commit/find_commits.go @@ -29,11 +29,11 @@ func (s *server) FindCommits(req *gitalypb.FindCommitsRequest, stream gitalypb.C // Use Gitaly's default branch lookup function because that is already // migrated. if revision := req.Revision; len(revision) == 0 && !req.GetAll() { - var err error - req.Revision, err = defaultBranchName(ctx, repo) + defaultBranch, err := repo.GetDefaultBranch(ctx) if err != nil { return helper.ErrInternal(fmt.Errorf("defaultBranchName: %v", err)) } + req.Revision = []byte(defaultBranch) } // Clients might send empty paths. That is an error for _, path := range req.Paths { diff --git a/internal/gitaly/service/commit/languages.go b/internal/gitaly/service/commit/languages.go index fc65f3aef..b9ef474d4 100644 --- a/internal/gitaly/service/commit/languages.go +++ b/internal/gitaly/service/commit/languages.go @@ -10,7 +10,6 @@ import ( "strings" "gitlab.com/gitlab-org/gitaly/v14/internal/git" - "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" "gitlab.com/gitlab-org/gitaly/v14/internal/helper" "gitlab.com/gitlab-org/gitaly/v14/internal/helper/text" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" @@ -27,11 +26,11 @@ func (s *server) CommitLanguages(ctx context.Context, req *gitalypb.CommitLangua revision := string(req.Revision) if revision == "" { - defaultBranch, err := ref.DefaultBranchName(ctx, repo) + defaultBranch, err := repo.GetDefaultBranch(ctx) if err != nil { return nil, err } - revision = string(defaultBranch) + revision = defaultBranch.String() } commitID, err := s.lookupRevision(ctx, repo, revision) diff --git a/internal/gitaly/service/commit/list_files.go b/internal/gitaly/service/commit/list_files.go index 7b1cf8b71..d06c4db8a 100644 --- a/internal/gitaly/service/commit/list_files.go +++ b/internal/gitaly/service/commit/list_files.go @@ -1,6 +1,7 @@ package commit import ( + "errors" "io" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" @@ -29,16 +30,14 @@ func (s *server) ListFiles(in *gitalypb.ListFilesRequest, stream gitalypb.Commit revision := string(in.GetRevision()) if len(revision) == 0 { - defaultBranch, err := defaultBranchName(stream.Context(), repo) - if err != nil { - return helper.ErrNotFoundf("revision not found %q", revision) - } - - if len(defaultBranch) == 0 { + defaultBranch, err := repo.GetDefaultBranch(stream.Context()) + if errors.Is(err, git.ErrNoDefaultBranch) { return helper.ErrFailedPreconditionf("repository does not have a default branch") + } else if err != nil { + return helper.ErrNotFoundf("revision not found %q", revision) } - revision = string(defaultBranch) + revision = defaultBranch.String() } contained, err := s.localrepo(repo).HasRevision(stream.Context(), git.Revision(revision)) diff --git a/internal/gitaly/service/commit/list_files_test.go b/internal/gitaly/service/commit/list_files_test.go index f07fd7658..e0f69a92b 100644 --- a/internal/gitaly/service/commit/list_files_test.go +++ b/internal/gitaly/service/commit/list_files_test.go @@ -1,14 +1,11 @@ package commit import ( - "context" "io" "testing" "github.com/stretchr/testify/require" - "gitlab.com/gitlab-org/gitaly/v14/internal/git" "gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest" - "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" "gitlab.com/gitlab-org/gitaly/v14/internal/testhelper" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -40,14 +37,9 @@ var defaultFiles = [][]byte{ } func TestListFiles_success(t *testing.T) { - defaultBranchName = func(context.Context, git.RepositoryExecutor) ([]byte, error) { - return []byte("test-do-not-touch"), nil - } - defer func() { - defaultBranchName = ref.DefaultBranchName - }() + cfg, repo, repoPath, client := setupCommitServiceWithRepo(t, true) - _, repo, _, client := setupCommitServiceWithRepo(t, true) + gittest.Exec(t, cfg, "-C", repoPath, "symbolic-ref", "HEAD", "refs/heads/test-do-not-touch") tests := []struct { desc string diff --git a/internal/gitaly/service/commit/server.go b/internal/gitaly/service/commit/server.go index 6669091e0..1ada86a09 100644 --- a/internal/gitaly/service/commit/server.go +++ b/internal/gitaly/service/commit/server.go @@ -7,7 +7,6 @@ import ( "gitlab.com/gitlab-org/gitaly/v14/internal/git/repository" "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/linguist" - "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/storage" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" ) @@ -21,8 +20,6 @@ type server struct { catfileCache catfile.Cache } -var defaultBranchName = ref.DefaultBranchName - // NewServer creates a new instance of a grpc CommitServiceServer func NewServer( cfg config.Cfg, diff --git a/internal/gitaly/service/operations/apply_patch.go b/internal/gitaly/service/operations/apply_patch.go index e4370a346..a2f2c0d73 100644 --- a/internal/gitaly/service/operations/apply_patch.go +++ b/internal/gitaly/service/operations/apply_patch.go @@ -11,7 +11,6 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "gitlab.com/gitlab-org/gitaly/v14/internal/git" - "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" "gitlab.com/gitlab-org/gitaly/v14/internal/helper" "gitlab.com/gitlab-org/gitaly/v14/internal/helper/text" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" @@ -20,8 +19,6 @@ import ( "google.golang.org/grpc/status" ) -var errNoDefaultBranch = errors.New("no default branch") - func (s *Server) UserApplyPatch(stream gitalypb.OperationService_UserApplyPatchServer) error { firstRequest, err := stream.Recv() if err != nil { @@ -60,15 +57,13 @@ func (s *Server) userApplyPatch(ctx context.Context, header *gitalypb.UserApplyP return fmt.Errorf("resolve target branch: %w", err) } - defaultBranch, err := ref.DefaultBranchName(ctx, repo) + defaultBranch, err := repo.GetDefaultBranch(ctx) if err != nil { return fmt.Errorf("default branch name: %w", err) - } else if defaultBranch == nil { - return errNoDefaultBranch } branchCreated = true - parentCommitID, err = repo.ResolveRevision(ctx, git.Revision(defaultBranch)+"^{commit}") + parentCommitID, err = repo.ResolveRevision(ctx, defaultBranch.Revision()+"^{commit}") if err != nil { return fmt.Errorf("resolve default branch commit: %w", err) } diff --git a/internal/gitaly/service/operations/apply_patch_test.go b/internal/gitaly/service/operations/apply_patch_test.go index da7f23268..bd35bbb83 100644 --- a/internal/gitaly/service/operations/apply_patch_test.go +++ b/internal/gitaly/service/operations/apply_patch_test.go @@ -117,7 +117,7 @@ To restore the original branch and stop patching, run "git am --abort". createFile("file", "base-content"), }, }, - error: status.Error(codes.Internal, "no default branch"), + error: status.Error(codes.Internal, "default branch name: no default branch"), }, { desc: "creating a new branch from HEAD works", @@ -294,6 +294,11 @@ To restore the original branch and stop patching, run "git am --abort". if baseCommit != "" { require.NoError(t, repo.UpdateRef(ctx, tc.baseReference, baseCommit, git.ZeroOID)) + + // Now that the repo has a ref, setup the default branch + if _, ok := tc.baseReference.Branch(); ok { + gittest.Exec(t, cfg, "-C", repoPath, "symbolic-ref", "HEAD", tc.baseReference.String()) + } } if tc.extraBranches != nil { diff --git a/internal/gitaly/service/ref/refs.go b/internal/gitaly/service/ref/refs.go index 8795771f9..7e149b674 100644 --- a/internal/gitaly/service/ref/refs.go +++ b/internal/gitaly/service/ref/refs.go @@ -27,13 +27,6 @@ const ( tagFormat = "%(objectname) %(objecttype) %(refname:lstrip=2)" ) -var ( - // We declare the following functions in variables so that we can override them in our tests - headReference = _headReference - // FindBranchNames is exported to be used in other packages - FindBranchNames = _findBranchNames -) - type findRefsOpts struct { cmdArgs []git.Option delim byte @@ -268,7 +261,10 @@ func (s *server) validateFindAllTagsRequest(request *gitalypb.FindAllTagsRequest return nil } -func _findBranchNames(ctx context.Context, repo git.RepositoryExecutor) ([][]byte, error) { +// FindBranchNames returns all branch names. +// +// Deprecated: Use localrepo.Repo.GetBranches instead. +func FindBranchNames(ctx context.Context, repo git.RepositoryExecutor) ([][]byte, error) { var names [][]byte cmd, err := repo.Exec(ctx, git.SubCmd{ @@ -296,38 +292,6 @@ func _findBranchNames(ctx context.Context, repo git.RepositoryExecutor) ([][]byt return names, nil } -func _headReference(ctx context.Context, repo git.RepositoryExecutor) ([]byte, error) { - var headRef []byte - - cmd, err := repo.Exec(ctx, git.SubCmd{ - Name: "rev-parse", - Flags: []git.Option{git.Flag{Name: "--symbolic-full-name"}}, - Args: []string{"HEAD"}, - }) - if err != nil { - return nil, err - } - - scanner := bufio.NewScanner(cmd) - scanner.Scan() - if err := scanner.Err(); err != nil { - return nil, err - } - headRef = scanner.Bytes() - - if err := cmd.Wait(); err != nil { - // If the ref pointed at by HEAD doesn't exist, the rev-parse fails - // returning the string `"HEAD"`, so we return `nil` without error. - if bytes.Equal(headRef, []byte("HEAD")) { - return nil, nil - } - - return nil, err - } - - return headRef, nil -} - // SetDefaultBranchRef overwrites the default branch ref for the repository func SetDefaultBranchRef(ctx context.Context, repo git.RepositoryExecutor, ref string, cfg config.Cfg) error { if err := repo.ExecAndWait(ctx, git.SubCmd{ @@ -339,65 +303,16 @@ func SetDefaultBranchRef(ctx context.Context, repo git.RepositoryExecutor, ref s return nil } -// DefaultBranchName looks up the name of the default branch given a repoPath -func DefaultBranchName(ctx context.Context, repo git.RepositoryExecutor) ([]byte, error) { - branches, err := FindBranchNames(ctx, repo) - if err != nil { - return nil, err - } - - // Return empty ref name if there are no branches - if len(branches) == 0 { - return nil, nil - } - - // Return first branch name if there's only one - if len(branches) == 1 { - return branches[0], nil - } - - hasDefaultRef, hasLegacyDefaultRef := false, false - headRef, err := headReference(ctx, repo) - if err != nil { - return nil, err - } - - for _, branch := range branches { - // Return HEAD if it exists and corresponds to a branch - if headRef != nil && bytes.Equal(headRef, branch) { - return headRef, nil - } - - if bytes.Equal(branch, git.DefaultRef) { - hasDefaultRef = true - } - - hasLegacyDefaultRef = hasLegacyDefaultRef || bytes.Equal(branch, git.LegacyDefaultRef) - } - - // Return the default ref if it exists - if hasDefaultRef { - return git.DefaultRef, nil - } - - if hasLegacyDefaultRef { - return git.LegacyDefaultRef, nil - } - - // If all else fails, return the first branch name - return branches[0], nil -} - // FindDefaultBranchName returns the default branch name for the given repository func (s *server) FindDefaultBranchName(ctx context.Context, in *gitalypb.FindDefaultBranchNameRequest) (*gitalypb.FindDefaultBranchNameResponse, error) { repo := s.localrepo(in.GetRepository()) - defaultBranchName, err := DefaultBranchName(ctx, repo) - if err != nil { + defaultBranch, err := repo.GetDefaultBranch(ctx) + if err != nil && !errors.Is(err, git.ErrNoDefaultBranch) { return nil, helper.ErrInternal(err) } - return &gitalypb.FindDefaultBranchNameResponse{Name: defaultBranchName}, nil + return &gitalypb.FindDefaultBranchNameResponse{Name: []byte(defaultBranch)}, nil } func parseSortKey(sortKey gitalypb.FindLocalBranchesRequest_SortBy) string { @@ -461,12 +376,12 @@ func (s *server) findAllBranches(in *gitalypb.FindAllBranchesRequest, stream git patterns := []string{"refs/heads", "refs/remotes"} if in.MergedOnly { - defaultBranchName, err := DefaultBranchName(stream.Context(), repo) + defaultBranch, err := repo.GetDefaultBranch(stream.Context()) if err != nil { return err } - args = append(args, git.Flag{Name: fmt.Sprintf("--merged=%s", string(defaultBranchName))}) + args = append(args, git.Flag{Name: fmt.Sprintf("--merged=%s", defaultBranch.String())}) if len(in.MergedBranches) > 0 { patterns = nil diff --git a/internal/gitaly/service/ref/refs_test.go b/internal/gitaly/service/ref/refs_test.go index 92199bdba..cbfb7383c 100644 --- a/internal/gitaly/service/ref/refs_test.go +++ b/internal/gitaly/service/ref/refs_test.go @@ -3,10 +3,8 @@ package ref import ( "bufio" "bytes" - "context" "fmt" "io" - "io/ioutil" "strings" "testing" "time" @@ -223,37 +221,6 @@ func TestInvalidRepoFindAllTagNamesRequest(t *testing.T) { } } -func TestHeadReference(t *testing.T) { - cfg, repo, _ := testcfg.BuildWithRepo(t) - - ctx, cancel := testhelper.Context() - defer cancel() - - headRef, err := headReference(ctx, localrepo.NewTestRepo(t, cfg, repo)) - require.NoError(t, err) - - require.Equal(t, git.LegacyDefaultRef, headRef) -} - -func TestHeadReferenceWithNonExistingHead(t *testing.T) { - cfg, repo, repoPath := testcfg.BuildWithRepo(t) - - // Write bad HEAD - require.NoError(t, ioutil.WriteFile(repoPath+"/HEAD", []byte("ref: refs/heads/nonexisting"), 0o644)) - defer func() { - // Restore HEAD - require.NoError(t, ioutil.WriteFile(repoPath+"/HEAD", []byte("ref: refs/heads/master"), 0o644)) - }() - - ctx, cancel := testhelper.Context() - defer cancel() - headRef, err := headReference(ctx, localrepo.NewTestRepo(t, cfg, repo)) - require.NoError(t, err) - if headRef != nil { - t.Fatal("Expected HEAD reference to be nil, got '", string(headRef), "'") - } -} - func TestSetDefaultBranchRef(t *testing.T) { cfg, repoProto, _ := testcfg.BuildWithRepo(t) repo := localrepo.NewTestRepo(t, cfg, repoProto) @@ -271,7 +238,7 @@ func TestSetDefaultBranchRef(t *testing.T) { { desc: "unknown ref", ref: "refs/heads/non_existent_ref", - expectedRef: string(git.LegacyDefaultRef), + expectedRef: git.LegacyDefaultRef.String(), }, } @@ -282,88 +249,14 @@ func TestSetDefaultBranchRef(t *testing.T) { require.NoError(t, SetDefaultBranchRef(ctx, repo, tc.ref, cfg)) - newRef, err := DefaultBranchName(ctx, repo) + newRef, err := repo.GetDefaultBranch(ctx) require.NoError(t, err) - require.Equal(t, tc.expectedRef, string(newRef)) + require.Equal(t, tc.expectedRef, newRef.String()) }) } } -func TestDefaultBranchName(t *testing.T) { - // We are going to override these functions during this test. Restore them after we're done - defer func() { - FindBranchNames = _findBranchNames - headReference = _headReference - }() - - cfg, repoProto, _ := testcfg.BuildWithRepo(t) - repo := localrepo.NewTestRepo(t, cfg, repoProto) - - testCases := []struct { - desc string - findBranchNames func(context.Context, git.RepositoryExecutor) ([][]byte, error) - headReference func(context.Context, git.RepositoryExecutor) ([]byte, error) - expected []byte - }{ - { - desc: "Get first branch when only one branch exists", - expected: []byte("refs/heads/foo"), - findBranchNames: func(context.Context, git.RepositoryExecutor) ([][]byte, error) { - return [][]byte{[]byte("refs/heads/foo")}, nil - }, - headReference: func(context.Context, git.RepositoryExecutor) ([]byte, error) { return nil, nil }, - }, - { - desc: "Get empy ref if no branches exists", - expected: nil, - findBranchNames: func(context.Context, git.RepositoryExecutor) ([][]byte, error) { - return [][]byte{}, nil - }, - headReference: func(context.Context, git.RepositoryExecutor) ([]byte, error) { return nil, nil }, - }, - { - desc: "Get the name of the head reference when more than one branch exists", - expected: []byte("refs/heads/bar"), - findBranchNames: func(context.Context, git.RepositoryExecutor) ([][]byte, error) { - return [][]byte{[]byte("refs/heads/foo"), []byte("refs/heads/bar")}, nil - }, - headReference: func(context.Context, git.RepositoryExecutor) ([]byte, error) { - return []byte("refs/heads/bar"), nil - }, - }, - { - desc: "Get `ref/heads/master` when several branches exist", - expected: git.LegacyDefaultRef, - findBranchNames: func(context.Context, git.RepositoryExecutor) ([][]byte, error) { - return [][]byte{[]byte("refs/heads/foo"), []byte("refs/heads/master"), []byte("refs/heads/bar")}, nil - }, - headReference: func(context.Context, git.RepositoryExecutor) ([]byte, error) { return nil, nil }, - }, - { - desc: "Get the name of the first branch when several branches exists and no other conditions are met", - expected: []byte("refs/heads/foo"), - findBranchNames: func(context.Context, git.RepositoryExecutor) ([][]byte, error) { - return [][]byte{[]byte("refs/heads/foo"), []byte("refs/heads/bar"), []byte("refs/heads/baz")}, nil - }, - headReference: func(context.Context, git.RepositoryExecutor) ([]byte, error) { return nil, nil }, - }, - } - - for _, testCase := range testCases { - FindBranchNames = testCase.findBranchNames - headReference = testCase.headReference - - ctx, cancel := testhelper.Context() - defer cancel() - defaultBranch, err := DefaultBranchName(ctx, repo) - require.NoError(t, err) - if !bytes.Equal(defaultBranch, testCase.expected) { - t.Fatalf("%s: expected %s, got %s instead", testCase.desc, testCase.expected, defaultBranch) - } - } -} - func TestSuccessfulFindDefaultBranchName(t *testing.T) { cfg, repo, repoPath, client := setupRefService(t) rpcRequest := &gitalypb.FindDefaultBranchNameRequest{Repository: repo} @@ -378,7 +271,7 @@ func TestSuccessfulFindDefaultBranchName(t *testing.T) { r, err := client.FindDefaultBranchName(ctx, rpcRequest) require.NoError(t, err) - require.Equal(t, r.GetName(), git.DefaultRef) + require.Equal(t, r.GetName(), []byte(git.DefaultRef)) } func TestSuccessfulFindDefaultBranchNameLegacy(t *testing.T) { @@ -390,7 +283,7 @@ func TestSuccessfulFindDefaultBranchNameLegacy(t *testing.T) { r, err := client.FindDefaultBranchName(ctx, rpcRequest) require.NoError(t, err) - require.Equal(t, r.GetName(), git.LegacyDefaultRef) + require.Equal(t, r.GetName(), []byte(git.LegacyDefaultRef)) } func TestEmptyFindDefaultBranchNameRequest(t *testing.T) { diff --git a/internal/gitaly/service/remote/fetch_internal_remote.go b/internal/gitaly/service/remote/fetch_internal_remote.go index 7eafcf23b..c49b530c1 100644 --- a/internal/gitaly/service/remote/fetch_internal_remote.go +++ b/internal/gitaly/service/remote/fetch_internal_remote.go @@ -8,6 +8,7 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "gitlab.com/gitlab-org/gitaly/v14/client" + "gitlab.com/gitlab-org/gitaly/v14/internal/git" "gitlab.com/gitlab-org/gitaly/v14/internal/git/localrepo" "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" @@ -61,12 +62,12 @@ func FetchInternalRemote( return status.Errorf(codes.Internal, "FetchInternalRemote: remote default branch: %v", err) } - defaultBranch, err := ref.DefaultBranchName(ctx, repo) - if err != nil { + defaultBranch, err := repo.GetDefaultBranch(ctx) + if err != nil && !errors.Is(err, git.ErrNoDefaultBranch) { return status.Errorf(codes.Internal, "FetchInternalRemote: default branch: %v", err) } - if !bytes.Equal(defaultBranch, remoteDefaultBranch) { + if defaultBranch.String() != string(remoteDefaultBranch) { if err := ref.SetDefaultBranchRef(ctx, repo, string(remoteDefaultBranch), cfg); err != nil { return status.Errorf(codes.Internal, "FetchInternalRemote: set default branch: %v", err) } diff --git a/internal/gitaly/service/remote/update_remote_mirror.go b/internal/gitaly/service/remote/update_remote_mirror.go index 8ab8f4ac9..3fd6e5a16 100644 --- a/internal/gitaly/service/remote/update_remote_mirror.go +++ b/internal/gitaly/service/remote/update_remote_mirror.go @@ -10,7 +10,6 @@ import ( "gitlab.com/gitlab-org/gitaly/v14/internal/git" "gitlab.com/gitlab-org/gitaly/v14/internal/git/localrepo" - "gitlab.com/gitlab-org/gitaly/v14/internal/gitaly/service/ref" "gitlab.com/gitlab-org/gitaly/v14/internal/helper" "gitlab.com/gitlab-org/gitaly/v14/internal/helper/text" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" @@ -103,8 +102,8 @@ func (s *server) updateRemoteMirror(stream gitalypb.RemoteService_UpdateRemoteMi return fmt.Errorf("get local references: %w", err) } - defaultBranch, err := ref.DefaultBranchName(ctx, repo) - if err != nil { + defaultBranch, err := repo.GetDefaultBranch(ctx) + if err != nil && !errors.Is(err, git.ErrNoDefaultBranch) { return fmt.Errorf("get default branch: %w", err) } @@ -195,7 +194,7 @@ func (s *server) updateRemoteMirror(stream gitalypb.RemoteService_UpdateRemoteMi } refspecs = append(refspecs, prefix+reference.String()) - if reference == git.ReferenceName(defaultBranch) { + if reference == defaultBranch { // The default branch needs to be pushed in the first batch of refspecs as some features // depend on it existing in the repository. The default branch may not exist in the repo // yet if this is the first mirroring push. |