syntax = "proto3";

package mesh.v1;

import "mesh/v1/commit.proto";
import "mesh/v1/git_model.proto";
import "mesh/v1/git_plumbing.proto";
import "mesh/v1/git_porcelain.proto";

option go_package = "atlassian.com/bitbucket/mesh/rpc/v1";
option java_multiple_files = true;
option java_outer_classname = "PullRequestProtos";
option java_package = "com.atlassian.bitbucket.mesh.rpc.v1";

message RpcBatchRescopePullRequestResponseFragment {
  //List of outcomes of analysis of the provided scope changes
  repeated RpcPullRequestRescopeOutcome outcomes = 1;
}

message RpcBatchRescopePullRequestRequest {
  //The primary repository for the rescope requests
  string repository = 1;
  RpcGitTimeouts timeouts = 2;
  //List of pull request scope changes, one per pull request
  repeated RpcPullRequestRescope rescopes = 10;
  //The maximum number of commits added and/or removed to return for RpcPullRequestUpdated outcomes
  optional int32 max_commits_per_update = 11;
  //The max length of commit messages to return. Commit messages longer than the provided limit will be truncated.
  optional int32 max_message_length = 12;
}

message RpcBatchRescopePullRequestResponse {
  //List of outcomes of analysis of the provided scope changes, one per provided RpcPullRequestRescope. Outcomes can
  //be matched to their RpcPullRequestRescope by rescope_id.
  repeated RpcPullRequestRescopeOutcome outcomes = 1;
}

message RpcBatchUpdatePullRequestRefsRequest {
  repeated RpcPullRequest pull_requests = 1;
}

message RpcBatchUpdatePullRequestRefsResponse {
  repeated RpcPullRequestRefUpdates ref_updates = 1;
}

/* Requests the deletion of the pull request. */
message RpcDeletePullRequestRequest {
  //The pull request to delete
  RpcPullRequest pull_request = 1;
}

/* Returns the refs updated from the deletion request. */
message RpcDeletePullRequestResponse {
  //Refs that are updated when the pull request is deleted.
  repeated RpcRefUpdate ref_updates = 1;
}

/* Requests the changes for a pull request. */
message RpcGetPullRequestChangesRequest {
  //The pull request to retrieve the changes for.
  RpcPullRequest pull_request = 1;
  //Timeouts to apply while retrieving changes.
  RpcGitTimeouts timeouts = 3;

  //Determines whether changes are returned for pull requests with unrelated from and to refs. If false,
  //which is the default, an error will be returned if the pull request's from and to refs do not share
  //a common ancestor.
  bool allow_unrelated = 13;
  //Diff options to apply, which can control behaviors like copy and rename detection.
  RpcDiffOptions diff_options = 10;
  //The maximum number of changes to return.
  int32 limit = 11;
  //Only include changes which match the provided paths.
  repeated bytes paths = 12;
}

/* Returns the changes for a pull request. */
message RpcGetPullRequestChangesResponseFragment {
  repeated RpcChange changes = 1;
}

/* Requests the commits included in a pull request. */
message RpcGetPullRequestCommitsRequest {
  //The pull request to retrieve commits for.
  RpcPullRequest pull_request = 1;
  //Timeouts to apply while retrieving commits.
  RpcGitTimeouts timeouts = 3;

  //When set, commit messages longer than the specified length are truncated. When set to 0, commit
  //messages are not returned. If omitted or set to a negative value no limit is applied.
  optional int32 max_message_length = 10;
  //Sort order to use for the commits
  RpcRevListOrder order = 11;

  //Range hints for pagination
  int32 limit = 12;
  int32 skip = 13;
}

/* Returns the commits for a pull request. These will be commits reachable from the pull request's
   from_ref that are not already reachable from the to_ref. */
message RpcGetPullRequestCommitsResponseFragment {
  repeated RpcCommit commits = 1;
}

/* Requests the diff for a pull request, optionally limited to specific files. */
message RpcGetPullRequestDiffRequest {
  //The pull request to retrieve commits for.
  RpcPullRequest pull_request = 1;
  //Timeouts to apply while retrieving commits.
  RpcGitTimeouts timeouts = 3;

  //Determines whether a diff is returned for pull requests with unrelated from and to refs. If false,
  //which is the default, an error will be returned if the pull request's from and to refs do not share
  //a common ancestor.
  bool allow_unrelated = 12;
  //Options that control how the diff is generated.
  RpcDiffOptions diff_options = 10;
  //If specified, limits the diff to only include the listed paths.
  repeated bytes paths = 11;
}

/* Requests the effective diff for a pull request. */
message RpcGetPullRequestEffectiveDiffRequest {
  //The pull request to retrieve the effective diff for.
  RpcPullRequest pull_request = 1;

  //Determines whether an effective diff is returned for pull requests with unrelated from and to refs.
  //If false, which is the default, an error will be returned if the pull request's from and to refs do
  //not share a common ancestor. If true, the null tree is treated as the common ancestor.
  bool allow_unrelated = 2;
}

/* Returns the effective diff for a pull request. */
message RpcGetPullRequestEffectiveDiffResponse {
  //The resolved effective diff.
  RpcPullRequestEffectiveDiff effective_diff = 1;
}

/* A fragment of a merge request. */
message RpcMergePullRequestFragment {
  oneof request_oneof {
    //Specifies the pull request to merge, and how. This must always be the first message. If the merge
    //completes without errors, the system will respond with a RpcRunPullRequestMergeHooks message.
    RpcMergePullRequestRequest merge_request = 1;
    //After RpcRunPullRequestMergeHooks, indicates the merge should be applied to the to_ref. If this
    //message is not sent, the merge will be discarded when the RPC request completes.
    RpcUpdateRef update_ref = 2;
  }
}

/* Requests merging the specified pull request. */
message RpcMergePullRequestRequest {
  RpcPullRequest pull_request = 1;
  RpcGitTimeouts timeouts = 3;

  //Determines whether pull requests with unrelated from and to refs can be merged. If false, which
  //is the default, an error will be returned if the pull request's from and to refs do not share a
  //common ancestor.
  bool allow_unrelated = 19;
  //The person to record as the author on any new commits. If the merge strategy does not create any
  //new commits, this will be ignored.
  RpcPerson author = 10;
  //The person to record as the committer on any new commits. If the merge strategy does not create
  //any new commits, this will be ignored.
  RpcPerson committer = 11;
  //The number of messages from merged commits to include in the merge commit's message, which may be
  //0 to omit any messages.
  int32 log = 15;
  //For strategies that append data to the provided message (e.g. squash merges), this limits how long
  //the resulting message can be. This limit is _not_ applied to "message" directly.
  int32 max_message_length = 16;
  //The message to use for the new commit. If "log" is non-zero, this message becomes the prefix for
  //the final message. Otherwise, it is used verbatim _if a new commit is created_.
  bytes message = 17;
  //The strategy to use when creating the merge. Note that some strategies do not actually create a
  //merge commit, and some may not create any new commits at all.
  RpcMergeStrategy strategy = 18;
}

/* A fragment of a pull request merge's response. */
message RpcMergePullRequestResponseFragment {
  oneof response_oneof {
    //After a merge is successfully performed, this will be the first fragment returned. It allows the
    //client to run hooks to validate the merge. Clients respond with an RpcUpdateRef fragment if the
    //merge should be accepted.
    RpcRunPullRequestMergeHooks run_merge_hooks = 1;
    //After a merge is accepted, this fragment describes the updates the merge performed. This will be
    //the final fragment the system sends.
    RpcMergeResponse merge_response = 2;
  }
}

/* Describes a pull request, which is used to merge changes from a source ref into a target, which
   may be in a different repository.

   Note: This might be initially confused with a request to run `git pull`, similar to RpcFetchRequest.
   Since `git pull` requires a work tree, which repositories maintained by the system do not have, there
   is no reason to support that command. That allows this model message to use the name. */
message RpcPullRequest {
  //The pull request's ID. This ID is _not_ globally unique, it's unique to the to_ref's repository.
  uint64 id = 1;
  //The pull request's current version. The exact triggers for this to update are not part of the
  //RPC contract; however, callers _must_ ensure the version changes when the latest_commit for
  //either the from_ref or to_ref changes, or if the to_ref's ID changes (if the client supports
  //changing the target).
  int32 version = 2;
  //The source ref, which will be merged into the to_ref.
  RpcPullRequestRef from_ref = 3;
  //The pull request's current state, which can be used to influence processing.
  RpcPullRequestState state = 4;
  //The target ref, to which the from_ref will be merged.
  RpcPullRequestRef to_ref = 5;
}

/* Describes the effective diff for a pull request, which is the two commits that should be used
   with diff-tree or diff to view changes and file diffs. */
message RpcPullRequestEffectiveDiff {
  //The baseline or ancestor commit. For diff-tree and diff, this commit would be listed first.
  string from_commit = 1;
  //Retrieving the effective diff may update refs in the repository. If any refs are changed,
  //those updates will be returned here.
  repeated RpcRefUpdate ref_updates = 3;
  //The target commit. For diff-tree and diff, this commit would be listed second.
  string to_commit = 2;
}

/* Describes one of the refs in a pull request. Since pull requests can be opened between different
   repositories, each ref has its own repository. */
message RpcPullRequestRef {
  //The repository to which the ref belongs.
  string repository = 1;
  //The ref's ID (always fully qualified).
  bytes id = 2;
  //The latest _known_ commit for the ref. This may or may not match the latest commit for the ref
  //in the repository, depending on whether the pull request is up to date or not.
  string latest_commit = 3;
}

/* Describes one or more updates to the public pull request refs for a pull request. This message type is used
   in RPCs that operate on multiple pull requests and where it is not immediately obvious from the context which
   pull request the RpcRefUpdate 'belongs' to. */
message RpcPullRequestRefUpdates {
  //The pull request ID
  uint64 id = 1;
  //The repository the pull request is targeting (the to_repository).
  string repository = 2;
  //Optional update to the pull request's public from ref
  RpcRefUpdate from_ref_update = 3;
  //Optional update to the pull request's public merge ref
  RpcRefUpdate merge_ref_update = 4;
}

/* Describes the pull request scope change */
message RpcPullRequestRescope {
  string from_repository = 1;
  string old_from_commit = 2;
  string old_to_commit = 3;
  optional string new_from_commit = 4;
  optional string new_to_commit = 5;

  //The rescope ID, which is NOT the pull request ID
  uint64 rescope_id = 7;
  string to_repository = 8;
}

/* The outcome of the pull request scope change */
message RpcPullRequestRescopeOutcome {

  /* The pull request has been declined */
  message Declined {
  }

  /* The pull request has been merged */
  message Merged {
    optional string merge_commit = 1;
  }

  /* The new state of the pull request could not be determined */
  message Unknown {
  }

  /* The pull request remains open, but commits have been added to and/or removed from its scope */
  message Updated {
    //List of commits that has been added to the scope of the pull request. This can be a partial list if more commits
    //were added to the scope than specified in RpcBulkRescopePullRequestRequest.max_commits_per_update
    repeated RpcCommit added_commits = 1;
    //The total number of commits that have been added to the pull request scope
    uint32 total_added_commits = 2;
    //List of commits that has been removed from the scope of the pull request. This can be a partial list if more
    //commits were removed from the scope than specified in RpcBulkRescopePullRequestRequest.max_commits_per_update
    repeated RpcCommit removed_commits = 3;
    //The total number of commits that have been removed from the pull request scope
    uint32 total_removed_commits = 4;
  }

  oneof outcome_oneof {
    Declined declined = 1;
    Merged merged = 2;
    Unknown unknown = 3;
    Updated updated = 4;
  }

  uint64 rescope_id = 5;
}

/* Defines the possible states a pull request can be in. The system may apply different processing for
   some operations depending on state. */
enum RpcPullRequestState {
  PR_STATE_UNSPECIFIED = 0;
  PR_STATE_OPEN = 1;
  PR_STATE_DECLINED = 2;
  PR_STATE_MERGED = 3;
}

/* Requests to run merge hooks for the given merge. */
message RpcRunPullRequestMergeHooks {
  //ID of the repository that contains the pending pull request merge. This will be _related_ to the to_ref
  //repository, but can be a different ID if a work tree, sandbox or quarantine environment has been set up
  //to stage the merge.
  string repository = 1;

  //The new merge commit.
  string merge_commit = 2;
}

message RpcTryPullRequestMergeResponse {
  RpcMergeConflicts conflicts = 1;
}

message RpcUpdatePullRequestRefsRequest {
  RpcPullRequest pull_request = 1;
}

message RpcUpdatePullRequestRefsResponse {
  //Optional updates to the pull request's public from ref and merge ref
  repeated RpcRefUpdate ref_updates = 1;
}
