in internal/gitaly/service/operations/rebase_confirmable.go [18:143]
func (s *Server) UserRebaseConfirmable(stream gitalypb.OperationService_UserRebaseConfirmableServer) error {
firstRequest, err := stream.Recv()
if err != nil {
return err
}
header := firstRequest.GetHeader()
if header == nil {
return structerr.NewInvalidArgument("empty UserRebaseConfirmableRequest.Header")
}
ctx := stream.Context()
if err := validateUserRebaseConfirmableHeader(ctx, s.locator, header); err != nil {
return structerr.NewInvalidArgument("%w", err)
}
quarantineDir, quarantineRepo, err := s.quarantinedRepo(ctx, header.GetRepository())
if err != nil {
return structerr.NewInternal("creating repo quarantine: %w", err)
}
objectHash, err := quarantineRepo.ObjectHash(ctx)
if err != nil {
return fmt.Errorf("detecting object hash: %w", err)
}
branch := git.NewReferenceNameFromBranchName(string(header.GetBranch()))
oldrev, err := objectHash.FromHex(header.GetBranchSha())
if err != nil {
return structerr.NewNotFound("%w", err)
}
remoteFetch := rebaseRemoteFetch{header: header}
startRevision, err := s.fetchStartRevision(ctx, quarantineRepo, remoteFetch)
if err != nil {
return structerr.NewInternal("%w", err)
}
committerSignature, err := git.SignatureFromRequest(header)
if err != nil {
return structerr.NewInvalidArgument("%w", err)
}
newrev, err := quarantineRepo.Rebase(
ctx,
startRevision.String(),
oldrev.String(),
localrepo.RebaseWithCommitter(committerSignature),
)
if err != nil {
var conflictErr *localrepo.RebaseConflictError
if errors.As(err, &conflictErr) {
conflictingFilesFromErr := conflictErr.ConflictError.ConflictedFiles()
conflictingFiles := make([][]byte, 0, len(conflictingFilesFromErr))
for _, conflictingFile := range conflictingFilesFromErr {
conflictingFiles = append(conflictingFiles, []byte(conflictingFile))
}
return structerr.NewFailedPrecondition("rebasing commits: %w", conflictErr).WithDetail(
&gitalypb.UserRebaseConfirmableError{
Error: &gitalypb.UserRebaseConfirmableError_RebaseConflict{
RebaseConflict: &gitalypb.MergeConflictError{
ConflictingFiles: conflictingFiles,
ConflictingCommitIds: []string{
startRevision.String(),
oldrev.String(),
},
},
},
},
)
}
return structerr.NewInternal("rebasing commits: %w", err)
}
if err := stream.Send(&gitalypb.UserRebaseConfirmableResponse{
UserRebaseConfirmableResponsePayload: &gitalypb.UserRebaseConfirmableResponse_RebaseSha{
RebaseSha: newrev.String(),
},
}); err != nil {
return structerr.NewInternal("send rebase sha: %w", err)
}
secondRequest, err := stream.Recv()
if err != nil {
return structerr.NewInternal("recv: %w", err)
}
if !secondRequest.GetApply() {
return structerr.NewFailedPrecondition("rebase aborted by client")
}
if err := s.updateReferenceWithHooks(
ctx,
header.GetRepository(),
header.GetUser(),
quarantineDir,
branch,
newrev,
oldrev,
header.GetGitPushOptions()...,
); err != nil {
var customHookErr updateref.CustomHookError
switch {
case errors.As(err, &customHookErr):
//nolint:gitaly-linters
return structerr.NewPermissionDenied("access check: %q", err).WithDetail(
&gitalypb.UserRebaseConfirmableError{
Error: &gitalypb.UserRebaseConfirmableError_AccessCheck{
AccessCheck: &gitalypb.AccessCheckError{
ErrorMessage: customHookErr.Error(),
},
},
},
)
}
return structerr.NewInternal("updating ref with hooks: %w", err)
}
return stream.Send(&gitalypb.UserRebaseConfirmableResponse{
UserRebaseConfirmableResponsePayload: &gitalypb.UserRebaseConfirmableResponse_RebaseApplied{
RebaseApplied: true,
},
})
}