// SPDX-License-Identifier: MIT syntax = "proto3"; package ermite; import "google/protobuf/timestamp.proto"; // IssueState is where an issue is in its life. enum IssueState { // Not set. In ListIssuesRequest.state it means every state. Never returned // by the server. ISSUE_STATE_UNSPECIFIED = 0; // The issue is open. ISSUE_STATE_OPEN = 1; // The issue is closed. ISSUE_STATE_CLOSED = 2; // Reserved for later use: awaiting moderation, owner-only. ISSUE_STATE_PENDING = 3; } // Issue is a discussion in a repository. message Issue { // Repo is the name of the repository. string repo = 1; // Number identifies the issue within its repository. int64 number = 2; // Title is the one-line title. string title = 3; // Body is the content of the issue. It may be empty. string body = 4; // State is where the issue is in its life. IssueState state = 5; // Author names who created the issue: the label of the token or session // that was used ("root" for the root token, "owner" for a web session), or, // for an issue approved from the public form, the unverified display name // the visitor typed (or "anonymous"). It is informational and never proves // identity: labels are not unique, the token may be gone, and a visitor can // type "owner". string author = 6; // CreatedAt is when the issue was created. google.protobuf.Timestamp created_at = 7; // UpdatedAt is when the issue last changed. google.protobuf.Timestamp updated_at = 8; // CommentCount is the number of comments on the issue. int32 comment_count = 9; } // IssueComment is a note on an issue. message IssueComment { // Id identifies the comment within its issue. Opaque. string id = 1; // Author names who wrote the comment, like Issue.author. string author = 2; // Text is the content of the comment. string text = 3; // CreatedAt is when the comment was written. google.protobuf.Timestamp created_at = 4; } // IssueService manages issues and their comments. // // Servers that implement this service list "issues" in // GetVersionResponse.features. Issues and merge requests of a repository share // one number sequence. When the issues mode of the repository is off, every // call answers not_found, as for a repository that does not exist. // // Reading (ListIssues, GetIssue) needs the same access as reading the // repository: nothing for a public one, the repo:read scope for a private one. // Writing (CreateIssue, AddIssueComment, CloseIssue, ReopenIssue) needs the // owner or a token with the issue:write scope on the repository; branch // prefixes do not restrict it. A caller without credentials gets // unauthenticated, one with an insufficient scope gets permission_denied, and // one that cannot read the repository gets not_found. // // Text fields are normalized to NFC and stripped of control and Unicode // bidirectional characters (line breaks and tabs stay in bodies and comments). // The title is one line of 1 to 120 code points; body and comment text are at // most 10,000 code points and a comment must not be blank. A text that breaks // a rule is rejected with invalid_argument. A comment on an issue that already // holds 1,000 comments gives resource_exhausted. Closing an issue that is not // open, or reopening one that is not closed, gives failed_precondition. // // The ordinary RPCs only return issues in state OPEN or CLOSED, and // ListIssues with state ISSUE_STATE_PENDING is invalid_argument. Submissions // from the public form wait as PendingIssue records, reachable only through // the three moderation RPCs (ListPendingIssues, ApproveIssue, RejectIssue). // These need owner rights (root, an owner session, or a token holding every // scope with no repository or branch limit); anyone else gets not_found, // whatever the request holds. For the owner, a malformed pending issue id is // not_found and a malformed repository name is invalid_argument. service IssueService { // CreateIssue opens an issue. Needs the issue:write scope. rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse); // ListIssues lists issues, highest number first, optionally in one state. rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse); // GetIssue returns an issue with its comments. rpc GetIssue(GetIssueRequest) returns (GetIssueResponse); // AddIssueComment adds a comment. Needs the issue:write scope. rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse); // CloseIssue closes an issue. Needs the issue:write scope. rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse); // ReopenIssue reopens an issue. Needs the issue:write scope. rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse); // ListPendingIssues lists issues awaiting moderation, oldest first. Owner // rights only; anyone else gets NOT_FOUND. rpc ListPendingIssues(ListPendingIssuesRequest) returns (ListPendingIssuesResponse); // ApproveIssue turns a pending issue into an open issue with a new number. // Owner rights only; anyone else gets NOT_FOUND. rpc ApproveIssue(ApproveIssueRequest) returns (ApproveIssueResponse); // RejectIssue discards a pending issue, optionally banning its submitter. // Owner rights only; anyone else gets NOT_FOUND. rpc RejectIssue(RejectIssueRequest) returns (RejectIssueResponse); } // CreateIssueRequest describes the issue to open. message CreateIssueRequest { // Repo is the repository name. string repo = 1; // Title is the one-line title. Required. string title = 2; // Body is the optional content. string body = 3; } // CreateIssueResponse holds the new issue. message CreateIssueResponse { // Issue is the created issue. Issue issue = 1; } // ListIssuesRequest selects a page of issues. message ListIssuesRequest { // Repo is the repository name. string repo = 1; // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means // every state. IssueState state = 2; // PageSize is the maximum number of issues to return. 0 means the server // default; values above the server maximum are lowered to it. int32 page_size = 3; // PageToken is the next_page_token of a previous response, to continue the // same listing. Empty for the first page. Other fields must be unchanged. string page_token = 4; } // ListIssuesResponse is one page of issues. message ListIssuesResponse { // Issues are the issues of this page, highest number first. repeated Issue issues = 1; // NextPageToken is passed as page_token to get the next page. Empty when // there is no next page. string next_page_token = 2; } // GetIssueRequest selects an issue. message GetIssueRequest { // Repo is the repository name. string repo = 1; // Number is the issue number. int64 number = 2; } // GetIssueResponse holds an issue with its comments. message GetIssueResponse { // Issue is the issue. Issue issue = 1; // Comments are every comment of the issue, oldest first. repeated IssueComment comments = 2; } // AddIssueCommentRequest describes the comment to add. message AddIssueCommentRequest { // Repo is the repository name. string repo = 1; // Number is the issue number. int64 number = 2; // Text is the content. Required. string text = 3; } // AddIssueCommentResponse holds the new comment. message AddIssueCommentResponse { // Comment is the created comment. IssueComment comment = 1; } // CloseIssueRequest names the issue to close. message CloseIssueRequest { // Repo is the repository name. string repo = 1; // Number is the issue number. int64 number = 2; } // CloseIssueResponse holds the issue after closing. message CloseIssueResponse { // Issue is the closed issue. Issue issue = 1; } // ReopenIssueRequest names the issue to reopen. message ReopenIssueRequest { // Repo is the repository name. string repo = 1; // Number is the issue number. int64 number = 2; } // ReopenIssueResponse holds the issue after reopening. message ReopenIssueResponse { // Issue is the reopened issue. Issue issue = 1; } // PendingIssue is an issue awaiting moderation. It has no number yet. message PendingIssue { // Id identifies the pending issue. Opaque internal id, not a number. string id = 1; // Repo is the name of the repository. string repo = 2; // Title is the one-line title. string title = 3; // Body is the content. It may be empty. string body = 4; // Author is the optional display name given by the anonymous submitter. It // may be empty or "anonymous", and is not verified: it never proves // identity (a visitor can type "owner"). It becomes Issue.author on approval. string author = 5; // CreatedAt is when the issue was submitted. google.protobuf.Timestamp created_at = 6; } // ListPendingIssuesRequest selects a page of pending issues. message ListPendingIssuesRequest { // Repo is the repository name. Empty means every repository. string repo = 1; // PageSize is the maximum number of issues to return. 0 means the server // default; values above the server maximum are lowered to it. int32 page_size = 2; // PageToken is the next_page_token of a previous response, to continue the // same listing. Empty for the first page. Other fields must be unchanged. string page_token = 3; } // ListPendingIssuesResponse is one page of pending issues. message ListPendingIssuesResponse { // Issues are the pending issues of this page, oldest first. repeated PendingIssue issues = 1; // NextPageToken is passed as page_token to get the next page. Empty when // there is no next page. string next_page_token = 2; } // ApproveIssueRequest names the pending issue to approve. message ApproveIssueRequest { // Repo is the repository name. string repo = 1; // Id is the PendingIssue.id. string id = 2; } // ApproveIssueResponse holds the approved issue. message ApproveIssueResponse { // Issue is the approved issue, with its new number and state // ISSUE_STATE_OPEN. Issue issue = 1; } // RejectIssueRequest names the pending issue to reject. message RejectIssueRequest { // Repo is the repository name. string repo = 1; // Id is the PendingIssue.id. string id = 2; // Ban also bans the submitter for a while. bool ban = 3; } // RejectIssueResponse is empty: the pending issue is gone. message RejectIssueResponse {}