syntax = "proto3";

package gitaly;

option go_package = "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb";

import "blob.proto";
import "shared.proto";
import "google/protobuf/timestamp.proto";

service RefService {
  rpc FindDefaultBranchName(FindDefaultBranchNameRequest) returns (FindDefaultBranchNameResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc FindAllBranchNames(FindAllBranchNamesRequest) returns (stream FindAllBranchNamesResponse) {
    option (op_type).op = ACCESSOR;

  }
  rpc FindAllTagNames(FindAllTagNamesRequest) returns (stream FindAllTagNamesResponse) {
    option (op_type).op = ACCESSOR;
  }
  // Find a Ref matching the given constraints. Response may be empty.
  rpc FindRefName(FindRefNameRequest) returns (FindRefNameResponse) {
    option (op_type).op = ACCESSOR;
  }
  // Return a stream so we can divide the response in chunks of branches
  rpc FindLocalBranches(FindLocalBranchesRequest) returns (stream FindLocalBranchesResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc FindAllBranches(FindAllBranchesRequest) returns (stream FindAllBranchesResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc FindAllTags(FindAllTagsRequest) returns (stream FindAllTagsResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc FindAllRemoteBranches(FindAllRemoteBranchesRequest) returns (stream FindAllRemoteBranchesResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc RefExists(RefExistsRequest) returns (RefExistsResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc CreateBranch(CreateBranchRequest) returns (CreateBranchResponse) {
    option (op_type) = {
      op: MUTATOR
      target_repository_field: "1"
    };
  }
  rpc DeleteBranch(DeleteBranchRequest) returns (DeleteBranchResponse) {
    option (op_type) = {
      op: MUTATOR
      target_repository_field: "1"
    };
  }
  rpc FindBranch(FindBranchRequest) returns (FindBranchResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc DeleteRefs(DeleteRefsRequest) returns (DeleteRefsResponse) {
    option (op_type) = {
      op: MUTATOR
      target_repository_field: "1"
    };
  }

  rpc ListBranchNamesContainingCommit(ListBranchNamesContainingCommitRequest) returns (stream ListBranchNamesContainingCommitResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc ListTagNamesContainingCommit(ListTagNamesContainingCommitRequest) returns (stream ListTagNamesContainingCommitResponse) {
    option (op_type).op = ACCESSOR;
  }

  rpc GetTagMessages(GetTagMessagesRequest) returns (stream GetTagMessagesResponse) {
    option (op_type).op = ACCESSOR;
  }

  // Returns commits that are only reachable from the ref passed
  rpc ListNewCommits(ListNewCommitsRequest) returns (stream ListNewCommitsResponse) {
    option (op_type).op = ACCESSOR;
  }

  rpc ListNewBlobs(ListNewBlobsRequest) returns (stream ListNewBlobsResponse) {
    option (op_type).op = ACCESSOR;
  }
  rpc PackRefs(PackRefsRequest) returns (PackRefsResponse) {
    option (op_type) = {
      op: MUTATOR
      target_repository_field: "1"
    };
  }
}

message ListNewBlobsRequest {
  Repository repository = 1;
  string commit_id = 2;
  // Limit the number of revs to be returned fro mgit-rev-list
  // If the limit is set to zero, all items will be returned
  uint32 limit = 3;
}

message ListNewBlobsResponse {
  repeated NewBlobObject new_blob_objects = 1;
}

message FindDefaultBranchNameRequest {
  Repository repository = 1;
}

message FindDefaultBranchNameResponse {
  bytes name = 1;
}

message FindAllBranchNamesRequest {
  Repository repository = 1;
}

message FindAllBranchNamesResponse {
  repeated bytes names = 1;
}

message FindAllTagNamesRequest {
  Repository repository = 1;
}

message FindAllTagNamesResponse {
  repeated bytes names = 1;
}

message FindRefNameRequest {
  Repository repository = 1;
  // Require that the resulting ref contains this commit as an ancestor
  string commit_id = 2;
  // Example prefix: "refs/heads/". Type bytes because that is the type of ref names.
  bytes prefix = 3;
}

message FindRefNameResponse {
  // Example name: "refs/heads/master". Cannot assume UTF8, so the type is bytes.
  bytes name = 1;
}

message FindLocalBranchesRequest {
  Repository repository = 1;
  enum SortBy {
    NAME = 0;
    UPDATED_ASC = 1;
    UPDATED_DESC = 2;
  }
  SortBy sort_by = 2;
}

message FindLocalBranchesResponse {
  repeated FindLocalBranchResponse branches = 1;
}

message FindLocalBranchResponse {
  bytes name = 1;
  string commit_id = 2;
  bytes commit_subject = 3;
  FindLocalBranchCommitAuthor commit_author = 4;
  FindLocalBranchCommitAuthor commit_committer = 5;
}

message FindLocalBranchCommitAuthor {
  bytes name = 1;
  bytes email = 2;
  google.protobuf.Timestamp date = 3;
}

message FindAllBranchesRequest {
  Repository repository = 1;
  // Only return branches that are merged into root ref
  bool merged_only = 2;
  // If merged_only is true, this is a list of branches from which we
  // return those merged into the root ref
  repeated bytes merged_branches = 3;
}

message FindAllBranchesResponse {
  message Branch {
    bytes name = 1;
    GitCommit target = 2;
  }
  repeated Branch branches = 1;
}

message FindAllTagsRequest {
  Repository repository = 1;
}

message FindAllTagsResponse {
  repeated Tag tags = 1;
}

message RefExistsRequest {
  Repository repository = 1;
  // Any ref, e.g. 'refs/heads/master' or 'refs/tags/v1.0.1'. Must start with 'refs/'.
  bytes ref = 2;
}

message RefExistsResponse {
  bool value = 1;
}

message CreateBranchRequest {
  Repository repository = 1;
  bytes name = 2;
  bytes start_point = 3;
}

message CreateBranchResponse {
  enum Status {
    OK = 0;
    ERR_EXISTS = 1;
    ERR_INVALID = 2;
    ERR_INVALID_START_POINT = 3;
  }
  Status status = 1;
  Branch branch = 2;
}

message DeleteBranchRequest {
  Repository repository = 1;
  bytes name = 2;
}

// Not clear if we need to do status signaling; we can add fields later.
message DeleteBranchResponse {}

message FindBranchRequest {
  Repository repository = 1;
  // Name can be 'master' but also 'refs/heads/master'
  bytes name = 2;
}

message FindBranchResponse {
  Branch branch = 1;
}

message DeleteRefsRequest{
  Repository repository = 1;
  // The following two fields are mutually exclusive
  repeated bytes except_with_prefix = 2;
  repeated bytes refs = 3;
}

message DeleteRefsResponse {
  string git_error = 1;
}

message ListBranchNamesContainingCommitRequest {
  Repository repository = 1;
  string commit_id = 2;

  // Limit the number of tag names to be returned
  // If the limit is set to zero, all items will be returned
  uint32 limit = 3;
}

message ListBranchNamesContainingCommitResponse {
  reserved 1;
  repeated bytes branch_names = 2;
}

message ListTagNamesContainingCommitRequest {
  Repository repository = 1;
  string commit_id = 2;

  // Limit the number of tag names to be returned
  // If the limit is set to zero, all items will be returned
  uint32 limit = 3;
}

message ListTagNamesContainingCommitResponse {
  reserved 1;
  repeated bytes tag_names = 2;
}

message GetTagMessagesRequest {
  reserved 2;
  reserved "tag_names";

  Repository repository = 1;
  repeated string tag_ids = 3;
}

message GetTagMessagesResponse {
  reserved 1;
  reserved "tag_name";

  bytes message = 2;
  // Only present for a new tag message
  string tag_id = 3;
}

message ListNewCommitsRequest {
  Repository repository = 1;
  string commit_id = 2;
}

message ListNewCommitsResponse {
  repeated GitCommit commits = 1;
}

message FindAllRemoteBranchesRequest {
  Repository repository = 1;
  string remote_name = 2;
}

message FindAllRemoteBranchesResponse {
  repeated Branch branches = 1;
}

message PackRefsRequest {
  Repository repository = 1;
  bool all_refs = 2;
}

message PackRefsResponse{}
