// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// https://developers.google.com/protocol-buffers/docs/proto3
syntax = "proto3";

import "github.com/golang/protobuf/ptypes/timestamp/timestamp.proto";

package maintpb;

message Mutation {
  GithubIssueMutation github_issue = 1; // issue-specific changes
  GithubMutation github = 3; // labels, milestones (not issue-specific)

  GitMutation git = 2;
  GerritMutation gerrit = 4;
}

message GithubMutation {
  string owner = 1;  // "golang"
  string repo = 2;  // "go"

  // Updated labels. (All must have id set at least)
  repeated GithubLabel labels = 3;

  // Updated milestones. (All must have id set at least)
  repeated GithubMilestone milestones = 4;
}

message GithubIssueMutation {
  string owner = 1;  // "golang"
  string repo = 2;  // "go"
  int32 number = 3;  // 1, 2, 3... (not the ID)

  // not_exist is set true if the issue has been found to not exist.
  // If true, the owner/repo/number fields above must still be set.
  // If a future issue mutation for the same number arrives without
  // not_exist set, then the issue comes back to life.
  bool not_exist = 13;

  int64 id = 12;  // unique across all repos

  GithubUser user = 4;   // only set for new/updated issues, not new comments
  repeated GithubUser assignees = 10; // who the issue is assigned to
  repeated int64 deleted_assignees = 11; // IDs of users to delete from the assignee list
  google.protobuf.Timestamp created = 5; // only needed on new issues
  google.protobuf.Timestamp updated = 6; // only set on updated issue text
  string title = 9; // issue title

  // body_change changes the body field (the top post, which isn't a comment).
  // It is now used in preference to the old body field.
  StringChange body_change = 31;
  // body was the old way to change the body, but it doesn't support removing the
  // body text, which is common on PRs. New mutations use body_change instead.
  string body = 7;

  bool no_milestone = 15; // true unsets any previously-set milestone; false ignored.
  // When setting a milestone, only the milestone_id must be set.
  // TODO: allow num or title to be used if Github only returns those? So far unneeded.
  // The num and title, if non-zero, are treated as if they were a GithubMutation.Milestone update.
  int64 milestone_id = 16; // sets milestone to this milestone id (e.g. 2386495, global?)
  int64 milestone_num = 17; // sets milestone to this milestone number (e.g. 2, per-repo)
  string milestone_title = 18;

  BoolChange closed = 19;
  BoolChange locked = 25;

  bool pull_request = 28;  // true is the issue is a Pull Request

  google.protobuf.Timestamp closed_at = 21;
  GithubUser closed_by = 22;

  repeated int64 remove_label = 23; // label IDs to remove
  repeated GithubLabel add_label = 24;

  repeated GithubIssueCommentMutation comment = 8;
  GithubIssueSyncStatus comment_status = 14;

  repeated GithubIssueEvent event = 26;  // new events to add
  GithubIssueSyncStatus event_status = 27;

  repeated GithubReview review = 29;  // new reviews to add
  GithubIssueSyncStatus review_status = 30;

  // Next tag: 32
}

// BoolChange represents a change to a boolean value.
// (Notably, the wrapper type permits representing a change to false.)
message BoolChange {
  bool val = 1;
}

// StringChange represents a change to a boolean value.
// (Notably, the wrapper type permits representing a change to the empty string.)
message StringChange {
  string val = 1;
}

message GithubLabel {
  int64 id = 1;
  string name = 2;
}

message GithubMilestone {
  int64 id = 1; // required

  // Following only need to be non-zero on changes:
  string title = 2;
  BoolChange closed = 3;
  int64 number = 4;
}

// See https://developer.github.com/v3/activity/events/types/#issuesevent
// for some info.
message GithubIssueEvent {
  // Required:
  int64 id = 1;

  // event_type can be one of "assigned", "unassigned", "labeled",
  // "unlabeled", "opened", "edited", "milestoned", "demilestoned",
  // "closed", "reopened", "referenced", "renamed" or anything else
  // that Github adds in the future.
  string event_type = 2;
  int64 actor_id = 3;
  google.protobuf.Timestamp created = 4; // time of the event

  // label is populated for "labeled" and "unlabeled" events.
  // The label will usually not have an ID, due to Github's API
  // not returning one.
  GithubLabel label = 5;

  // milestone is populated for "milestoned" and "demilestoned" events.
  // The label will usually not have an ID, due to Github's API
  // not returning one.
  GithubMilestone milestone = 6;

  // For "assigned", "unassigned":
  int64 assignee_id = 7; // always same as actor_id it seems? Github API doesn't say.
  int64 assigner_id = 8;

  // For "referenced", "closed":
  GithubCommit commit = 9;

  // For "renamed" events:
  string rename_from = 11;
  string rename_to = 12;

  int64 reviewer_id = 13;
  int64 review_requester_id = 14;
  GithubTeam team_reviewer = 16;
  // Contents of a dismissed review event, see dismissed_review in
  // https://developer.github.com/v3/issues/events/ for more info
  GithubDismissedReviewEvent dismissed_review = 15;

  // other_json is usually empty. If Github adds event types or fields
  // in the future, this captures those added fields. If non-empty it
  // will be a JSON object with the fields that weren't understood.
  bytes other_json = 10;

  // Next tag: 17.
}

// Contents of a dismissed review event - when someone leaves a
// review requesting changes and someone else dismisses it. See
// https://developer.github.com/v3/issues/events for more information.
message GithubDismissedReviewEvent {
  int64 review_id = 1; // ID of the review being dismissed
  reserved 2; // Old int64 "state" field. Do not use.
  string dismissal_message = 3;
  string state = 4; // commented, approved, changes_requested
}

message GithubCommit {
  string owner = 1;     // "golang"
  string repo = 2;      // "go"
  string commit_id = 3; // "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
}

// Contents of a pull request review - when someone
// comments, requests changes, or approves changes
// on a pull request. See
// https://developer.github.com/v3/pulls/reviews/ for more information.
message GithubReview {
  // Required:
  int64 id = 1;

  int64 actor_id = 2;
  google.protobuf.Timestamp created = 3;  // time of the event
  string body = 4;                        // body of the review comment
  string state = 5;  // COMMENTED, APPROVED, CHANGES_REQUESTED
  string commit_id = 6;
  string actor_association = 7;

  // other_json is usually empty.
  bytes other_json = 8;

  // Next tag: 9
}

// GithubIssueSyncStatus notes where syncing is at for comments
// on an issue,
// This mutation type is only made at/after the same top-level mutation
// which created the corresponding comments.
message GithubIssueSyncStatus {
  // server_date is the "Date" response header from Github for the
  // final HTTP response.
  google.protobuf.Timestamp server_date = 1;
}

message GithubIssueCommentMutation {
  int64 id = 1;
  GithubUser user = 2; // not present in edits later
  string body = 3;   // may not be present in edits later (if only reactions changed? TODO: investigate)
  google.protobuf.Timestamp created = 4; // not present in edits later
  google.protobuf.Timestamp updated = 5;
}

message GithubUser {
  int64 id = 1;
  string login = 2;
}

message GithubTeam {
  int64 id = 1;
  string slug = 2;
}

message GitMutation {
  GitRepo repo = 1;

  // commit adds a commit, or adds new information to a commit if fields
  // are added in the future.
  GitCommit commit = 2;
}

// GitRepo identifies a git repo being mutated.
message GitRepo {
  // If go_repo is set, it identifies a go.googlesource.com/<go_repo> repo.
  string go_repo = 1;

  // TODO: code.googlesource.com and github repos later.
}

message GitCommit {
  string sha1 = 1; // the full lowercase 40-hex-byte sha1 sum

  // raw is the "git cat-file commit $sha1" output.
  bytes raw = 2;

  GitDiffTree diff_tree = 3;
}

// git diff-tree --numstat oldtree newtree
message GitDiffTree {
  repeated GitDiffTreeFile file = 1;
}

// GitDiffTreeFile represents one line of `git diff-tree --numstat` output.
message GitDiffTreeFile {
  string file = 1;
  int64  added = 2;
  int64  deleted = 3;
  bool   binary = 4;
}

message GerritMutation {
  // Project is the Gerrit server and project, without scheme (https implied) or
  // trailing slash.
  string project = 1; // "go.googlesource.com/go", "go.googlesource.com/net", etc

  // Commits to add.
  repeated GitCommit commits = 2;

  // git refs to update.
  repeated GitRef refs = 3;

  // deleted_refs are ref names to delete.
  repeated string deleted_refs = 4;
}

message GitRef {
  // ref is the git ref name, such as:
  //    HEAD
  //    refs/heads/master
  //    refs/changes/00/14700/1
  //    refs/changes/00/14700/meta
  //    refs/meta/config
  string ref = 1;

  // sha1 is the lowercase hex sha1
  string sha1 = 2;
}
