fix: [CODE-2717]: Modify Sync to take DefaultBranch as input (#2962)

This commit is contained in:
Johannes Batzill 2024-11-11 23:18:28 +00:00 committed by Harness
parent 4d4917eddc
commit ccce5ad646
5 changed files with 102 additions and 45 deletions

View File

@ -314,16 +314,12 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
log.Info().Msg("sync repository")
defaultBranch, err := r.syncGitRepository(ctx, &systemPrincipal, repo, cloneURLWithAuth)
err = r.syncGitRepository(ctx, &systemPrincipal, repo, cloneURLWithAuth)
if err != nil {
return fmt.Errorf("failed to sync git repository from '%s': %w", input.CloneURL, err)
}
log.Info().Msgf("successfully synced repository (returned default branch: '%s')", defaultBranch)
if defaultBranch == "" {
defaultBranch = r.defaultBranch
}
log.Info().Msgf("successfully synced repository (with default branch: %q)", repo.DefaultBranch)
log.Info().Msg("update repo in DB")
@ -333,7 +329,6 @@ func (r *Repository) Handle(ctx context.Context, data string, _ job.ProgressRepo
}
repo.GitUID = gitUID
repo.DefaultBranch = defaultBranch
repo.State = enum.RepoStateActive
return nil
@ -463,23 +458,24 @@ func (r *Repository) syncGitRepository(ctx context.Context,
principal *types.Principal,
repo *types.Repository,
sourceCloneURL string,
) (string, error) {
) error {
writeParams, err := r.createRPCWriteParams(ctx, principal, repo)
if err != nil {
return "", err
return err
}
syncOut, err := r.git.SyncRepository(ctx, &git.SyncRepositoryParams{
_, err = r.git.SyncRepository(ctx, &git.SyncRepositoryParams{
WriteParams: writeParams,
Source: sourceCloneURL,
CreateIfNotExists: false,
RefSpecs: []string{"refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"},
DefaultBranch: repo.DefaultBranch,
})
if err != nil {
return "", fmt.Errorf("failed to sync repository: %w", err)
return fmt.Errorf("failed to sync repository: %w", err)
}
return syncOut.DefaultBranch, nil
return nil
}
func (r *Repository) deleteGitRepository(ctx context.Context,

View File

@ -96,14 +96,22 @@ func (g *Git) HasBranches(
func (g *Git) IsBranchExist(ctx context.Context, repoPath, name string) (bool, error) {
cmd := command.New("show-ref",
command.WithFlag("--verify", BranchPrefix+name),
command.WithFlag("--exists", BranchPrefix+name),
)
err := cmd.Run(ctx,
command.WithDir(repoPath),
)
if err != nil {
return false, fmt.Errorf("failed to check if branch '%s' exist: %w", name, err)
if cmdERR := command.AsError(err); cmdERR != nil && cmdERR.IsExitCode(2) {
// git returns exit code 2 in case the ref doesn't exist.
// On success it would be 0 and no error would be returned in the first place.
// Any other exit code we fall through to default error handling.
// https://git-scm.com/docs/git-show-ref#Documentation/git-show-ref.txt---exists
return false, nil
}
if err != nil {
return false, processGitErrorf(err, "failed to check if branch %q exist", name)
}
return true, nil
}

View File

@ -24,6 +24,7 @@ import (
"strings"
"time"
"github.com/harness/gitness/errors"
"github.com/harness/gitness/git/command"
"github.com/rs/zerolog/log"
@ -98,27 +99,28 @@ func (g *Git) SetDefaultBranch(
ctx context.Context,
repoPath string,
defaultBranch string,
allowEmpty bool,
ignoreBranchExistance bool,
) error {
if repoPath == "" {
return ErrRepositoryPathEmpty
}
// if requested, error out if branch doesn't exist. Otherwise, blindly set it.
exist, err := g.IsBranchExist(ctx, repoPath, defaultBranch)
if err != nil {
log.Ctx(ctx).Err(err).Msgf("failed to set default branch")
}
if !allowEmpty && !exist {
// TODO: ensure this returns not found error to caller
return fmt.Errorf("branch '%s' does not exist", defaultBranch)
if !ignoreBranchExistance {
// best effort try to check for existence - technically someone else could delete it in the meanwhile.
exist, err := g.IsBranchExist(ctx, repoPath, defaultBranch)
if err != nil {
return fmt.Errorf("failed to check if branch exists: %w", err)
}
if !exist {
return errors.NotFound("branch %q does not exist", defaultBranch)
}
}
// change default branch
cmd := command.New("symbolic-ref",
command.WithArg("HEAD", gitReferenceNamePrefixBranch+defaultBranch),
)
err = cmd.Run(ctx, command.WithDir(repoPath))
err := cmd.Run(ctx, command.WithDir(repoPath))
if err != nil {
return processGitErrorf(err, "failed to set new default branch")
}
@ -130,6 +132,26 @@ func (g *Git) SetDefaultBranch(
func (g *Git) GetDefaultBranch(
ctx context.Context,
repoPath string,
) (string, error) {
rawBranchRef, err := g.GetSymbolicRefHeadRaw(ctx, repoPath)
if err != nil {
return "", fmt.Errorf("failed to get raw symbolic ref HEAD: %w", err)
}
branchName := strings.TrimPrefix(
strings.TrimSpace(
rawBranchRef,
),
BranchPrefix,
)
return branchName, nil
}
// GetSymbolicRefHeadRaw returns the raw output of the symolic-ref command for HEAD.
func (g *Git) GetSymbolicRefHeadRaw(
ctx context.Context,
repoPath string,
) (string, error) {
if repoPath == "" {
return "", ErrRepositoryPathEmpty
@ -144,7 +166,7 @@ func (g *Git) GetDefaultBranch(
command.WithDir(repoPath),
command.WithStdout(output))
if err != nil {
return "", processGitErrorf(err, "failed to get default branch")
return "", processGitErrorf(err, "failed to get value of symbolic ref HEAD from git")
}
return output.String(), nil

View File

@ -109,6 +109,10 @@ type SyncRepositoryParams struct {
// RefSpecs [OPTIONAL] allows to override the refspecs that are being synced from the remote repository.
// By default all references present on the remote repository will be fetched (including scm internal ones).
RefSpecs []string
// DefaultBranch [OPTIONAL] allows to override the default branch of the repository.
// If empty, the default branch will be set to match the remote repository's default branch.
// WARNING: If the remote repo is empty and no value is provided, an api.ErrNoDefaultBranch error is returned.
DefaultBranch string
}
type SyncRepositoryOutput struct {
@ -130,7 +134,15 @@ type HashRepositoryOutput struct {
}
type UpdateDefaultBranchParams struct {
WriteParams
// BranchName is the name of the branch
// BranchName is the name of the branch (not the full reference).
BranchName string
}
type GetDefaultBranchParams struct {
ReadParams
}
type GetDefaultBranchOutput struct {
// BranchName is the name of the branch (not the full reference).
BranchName string
}
@ -259,7 +271,7 @@ func (s *Service) SyncRepository(
}
// the default branch doesn't matter for a sync,
// we create an empty repo and the head will by updated as part of the Sync.
// we create an empty repo and the head will by updated later.
const syncDefaultBranch = "main"
if err = s.createRepositoryInternal(
ctx,
@ -278,24 +290,22 @@ func (s *Service) SyncRepository(
// sync repo content
err = s.git.Sync(ctx, repoPath, params.Source, params.RefSpecs)
if err != nil {
return nil, fmt.Errorf("SyncRepository: failed to sync git repo: %w", err)
return nil, fmt.Errorf("failed to sync from source repo: %w", err)
}
// get remote default branch
defaultBranch, err := s.git.GetRemoteDefaultBranch(ctx, params.Source)
if errors.Is(err, api.ErrNoDefaultBranch) {
return &SyncRepositoryOutput{
DefaultBranch: "",
}, nil
}
if err != nil {
return nil, fmt.Errorf("SyncRepository: failed to get default branch from repo: %w", err)
defaultBranch := params.DefaultBranch
if defaultBranch == "" {
// get default branch from remote repo (returns api.ErrNoDefaultBranch if repo is empty!)
defaultBranch, err = s.git.GetRemoteDefaultBranch(ctx, params.Source)
if err != nil {
return nil, fmt.Errorf("failed to get default branch from source repo: %w", err)
}
}
// set default branch
err = s.git.SetDefaultBranch(ctx, repoPath, defaultBranch, true)
if err != nil {
return nil, fmt.Errorf("SyncRepository: failed to set default branch of repo: %w", err)
return nil, fmt.Errorf("failed to set default branch of repo: %w", err)
}
return &SyncRepositoryOutput{
@ -329,7 +339,8 @@ func (s *Service) HashRepository(ctx context.Context, params *HashRepositoryPara
}()
// add default branch to hash
defaultBranch, err := s.git.GetDefaultBranch(goCtx, repoPath)
// IMPORTANT: Has to stay as is to ensure hash consistency! (e.g. "refs/heads/main/n")
defaultBranchRef, err := s.git.GetSymbolicRefHeadRaw(goCtx, repoPath)
if err != nil {
hashChan <- hash.SourceNext{
Err: fmt.Errorf("HashRepository: failed to get default branch: %w", err),
@ -338,7 +349,7 @@ func (s *Service) HashRepository(ctx context.Context, params *HashRepositoryPara
}
hashChan <- hash.SourceNext{
Data: hash.SerializeHead(defaultBranch),
Data: hash.SerializeHead(defaultBranchRef),
}
err = s.git.WalkReferences(goCtx, repoPath, func(wre api.WalkReferencesEntry) error {
@ -515,6 +526,26 @@ func (s *Service) GetRepositorySize(
}, nil
}
// GetDefaultBranch returns the default branch of the repo.
func (s *Service) GetDefaultBranch(
ctx context.Context,
params *GetDefaultBranchParams,
) (*GetDefaultBranchOutput, error) {
if err := params.Validate(); err != nil {
return nil, err
}
repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID)
dfltBranch, err := s.git.GetDefaultBranch(ctx, repoPath)
if err != nil {
return nil, fmt.Errorf("failed to get repo default branch: %w", err)
}
return &GetDefaultBranchOutput{
BranchName: dfltBranch,
}, nil
}
// UpdateDefaultBranch updates the default branch of the repo.
func (s *Service) UpdateDefaultBranch(
ctx context.Context,
@ -531,7 +562,7 @@ func (s *Service) UpdateDefaultBranch(
err := s.git.SetDefaultBranch(ctx, repoPath, params.BranchName, false)
if err != nil {
return fmt.Errorf("UpdateDefaultBranch: failed to update repo default branch %q: %w",
return fmt.Errorf("failed to update repo default branch %q: %w",
params.BranchName, err)
}
return nil

View File

@ -17,8 +17,8 @@ package git
import (
"context"
"fmt"
"strings"
"github.com/harness/gitness/git/api"
"github.com/harness/gitness/git/merge"
"golang.org/x/sync/errgroup"
@ -44,7 +44,7 @@ func (s *Service) Summary(
if err != nil {
return SummaryOutput{}, err
}
defaultBranch = strings.TrimSpace(defaultBranch)
defaultBranchRef := api.GetReferenceFromBranchName(defaultBranch)
g, ctx := errgroup.WithContext(ctx)
@ -52,7 +52,7 @@ func (s *Service) Summary(
g.Go(func() error {
var err error
commitCount, err = merge.CommitCount(ctx, repoPath, "", defaultBranch)
commitCount, err = merge.CommitCount(ctx, repoPath, "", defaultBranchRef)
return err
})