func()

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,
		},
	})
}