syntax = "proto3";

package gitaly;

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

import "lint.proto";
import "shared.proto";

service DiffService {
  // Returns stream of CommitDiffResponse with patches chunked over messages
  rpc CommitDiff(CommitDiffRequest) returns (stream CommitDiffResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
  // Return a stream so we can divide the response in chunks of deltas
  rpc CommitDelta(CommitDeltaRequest) returns (stream CommitDeltaResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
  rpc RawDiff(RawDiffRequest) returns (stream RawDiffResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
  rpc RawPatch(RawPatchRequest) returns (stream RawPatchResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
  rpc DiffStats(DiffStatsRequest) returns (stream DiffStatsResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
  // Return a list of files changed along with the status of each file
  rpc FindChangedPaths(FindChangedPathsRequest) returns (stream FindChangedPathsResponse) {
    option (op_type) = {
      op: ACCESSOR
    };
  }
}

message CommitDiffRequest {
  enum DiffMode {
    // DEFAULT is the standard diff mode and results in a linewise diff for textfiles.
    DEFAULT = 0;
    // WORDDIFF is a word diff and computes the diff for whitespace separated words instead of for whole lines.
    WORDDIFF = 1;
  }

  Repository repository = 1 [(target_repository)=true];
  string left_commit_id = 2;
  string right_commit_id = 3;
  bool ignore_whitespace_change = 4;
  repeated bytes paths = 5;
  bool collapse_diffs = 6;
  bool enforce_limits = 7;

  // These limits are only enforced when enforce_limits == true.
  int32 max_files = 8;
  int32 max_lines = 9;
  int32 max_bytes = 10;
  // Limitation of a single diff patch,
  // patches surpassing this limit are pruned by default.
  // If this is 0 you will get back empty patches.
  int32 max_patch_bytes = 14;

  // These limits are only enforced if collapse_diffs == true.
  int32 safe_max_files = 11;
  int32 safe_max_lines = 12;
  int32 safe_max_bytes = 13;

  // DiffMode is the mode used for generating the diff. Please refer to the enum declaration for supported modes.
  DiffMode diff_mode = 15;
}

// A CommitDiffResponse corresponds to a single changed file in a commit.
message CommitDiffResponse {
  reserved 8;

  bytes from_path = 1;
  bytes to_path = 2;
  // Blob ID as returned via `git diff --full-index`
  string from_id = 3;
  string to_id = 4;
  int32 old_mode = 5;
  int32 new_mode = 6;
  bool binary = 7;
  bytes raw_patch_data = 9;
  bool end_of_patch = 10;
  // Indicates the diff file at which we overflow according to the limitations sent,
  // in which case only this attribute will be set.
  bool overflow_marker = 11;
  // Indicates the patch surpassed a "safe" limit and was therefore pruned, but
  // the client may still request the full patch on a separate request.
  bool collapsed = 12;
  // Indicates the patch was pruned since it surpassed a hard limit, and can
  // therefore not be expanded.
  bool too_large = 13;
}

message CommitDeltaRequest {
  Repository repository = 1 [(target_repository)=true];
  string left_commit_id = 2;
  string right_commit_id = 3;
  repeated bytes paths = 4;
}

message CommitDelta {
  bytes from_path = 1;
  bytes to_path = 2;
  // Blob ID as returned via `git diff --full-index`
  string from_id = 3;
  string to_id = 4;
  int32 old_mode = 5;
  int32 new_mode = 6;
}

message CommitDeltaResponse {
  repeated CommitDelta deltas = 1;
}

message RawDiffRequest {
  Repository repository = 1 [(target_repository)=true];
  string left_commit_id = 2;
  string right_commit_id = 3;
}

message RawDiffResponse {
  bytes data = 1;
}

message RawPatchRequest {
  Repository repository = 1 [(target_repository)=true];
  string left_commit_id = 2;
  string right_commit_id = 3;
}

message RawPatchResponse {
  bytes data = 1;
}

message DiffStatsRequest {
  Repository repository = 1 [(target_repository)=true];
  string left_commit_id = 2;
  string right_commit_id = 3;
}

message DiffStats {
  bytes path = 1;
  int32 additions = 2;
  int32 deletions = 3;
  bytes old_path = 4;
}

message DiffStatsResponse {
  repeated DiffStats stats = 1;
}

// Given a list of commits, return the files changed. Each commit is compared
// to its parent. Merge commits will show files which are different to all of
// its parents.
message FindChangedPathsRequest {
  Repository repository = 1 [(target_repository)=true];
  repeated string commits = 2;
}

// Returns a list of files that have been changed in the commits given
message FindChangedPathsResponse {
  repeated ChangedPaths paths = 1;
}

// Includes the path of the file, and the status of the change
message ChangedPaths {
  enum Status {
    ADDED = 0;
    MODIFIED = 1;
    DELETED = 2;
    TYPE_CHANGE = 3;
    COPIED = 4;
  }

  bytes path = 1;
  Status status = 2;
}
