1// SPDX-License-Identifier: MIT
2
3syntax = "proto3";
4
5package ermite;
6
7import "google/protobuf/timestamp.proto";
8
9// IssueState is where an issue is in its life.
10enum IssueState {
11 // Not set. In ListIssuesRequest.state it means every state. Never returned
12 // by the server.
13 ISSUE_STATE_UNSPECIFIED = 0;
14 // The issue is open.
15 ISSUE_STATE_OPEN = 1;
16 // The issue is closed.
17 ISSUE_STATE_CLOSED = 2;
18 // Reserved for later use: awaiting moderation, owner-only.
19 ISSUE_STATE_PENDING = 3;
20}
21
22// Issue is a discussion in a repository.
23message Issue {
24 // Repo is the name of the repository.
25 string repo = 1;
26 // Number identifies the issue within its repository.
27 int64 number = 2;
28 // Title is the one-line title.
29 string title = 3;
30 // Body is the content of the issue. It may be empty.
31 string body = 4;
32 // State is where the issue is in its life.
33 IssueState state = 5;
34 // Author names who created the issue: the label of the token or session
35 // that was used ("root" for the root token, "owner" for a web session), or,
36 // for an issue approved from the public form, the unverified display name
37 // the visitor typed (or "anonymous"). It is informational and never proves
38 // identity: labels are not unique, the token may be gone, and a visitor can
39 // type "owner".
40 string author = 6;
41 // CreatedAt is when the issue was created.
42 google.protobuf.Timestamp created_at = 7;
43 // UpdatedAt is when the issue last changed.
44 google.protobuf.Timestamp updated_at = 8;
45 // CommentCount is the number of comments on the issue.
46 int32 comment_count = 9;
47}
48
49// IssueComment is a note on an issue.
50message IssueComment {
51 // Id identifies the comment within its issue. Opaque.
52 string id = 1;
53 // Author names who wrote the comment, like Issue.author.
54 string author = 2;
55 // Text is the content of the comment.
56 string text = 3;
57 // CreatedAt is when the comment was written.
58 google.protobuf.Timestamp created_at = 4;
59}
60
61// IssueService manages issues and their comments.
62//
63// Servers that implement this service list "issues" in
64// GetVersionResponse.features. Issues and merge requests of a repository share
65// one number sequence. When the issues mode of the repository is off, every
66// call answers not_found, as for a repository that does not exist.
67//
68// Reading (ListIssues, GetIssue) needs the same access as reading the
69// repository: nothing for a public one, the repo:read scope for a private one.
70// Writing (CreateIssue, AddIssueComment, CloseIssue, ReopenIssue) needs the
71// owner or a token with the issue:write scope on the repository; branch
72// prefixes do not restrict it. A caller without credentials gets
73// unauthenticated, one with an insufficient scope gets permission_denied, and
74// one that cannot read the repository gets not_found.
75//
76// Text fields are normalized to NFC and stripped of control and Unicode
77// bidirectional characters (line breaks and tabs stay in bodies and comments).
78// The title is one line of 1 to 120 code points; body and comment text are at
79// most 10,000 code points and a comment must not be blank. A text that breaks
80// a rule is rejected with invalid_argument. A comment on an issue that already
81// holds 1,000 comments gives resource_exhausted. Closing an issue that is not
82// open, or reopening one that is not closed, gives failed_precondition.
83//
84// The ordinary RPCs only return issues in state OPEN or CLOSED, and
85// ListIssues with state ISSUE_STATE_PENDING is invalid_argument. Submissions
86// from the public form wait as PendingIssue records, reachable only through
87// the three moderation RPCs (ListPendingIssues, ApproveIssue, RejectIssue).
88// These need owner rights (root, an owner session, or a token holding every
89// scope with no repository or branch limit); anyone else gets not_found,
90// whatever the request holds. For the owner, a malformed pending issue id is
91// not_found and a malformed repository name is invalid_argument.
92service IssueService {
93 // CreateIssue opens an issue. Needs the issue:write scope.
94 rpc CreateIssue(CreateIssueRequest) returns (CreateIssueResponse);
95 // ListIssues lists issues, highest number first, optionally in one state.
96 rpc ListIssues(ListIssuesRequest) returns (ListIssuesResponse);
97 // GetIssue returns an issue with its comments.
98 rpc GetIssue(GetIssueRequest) returns (GetIssueResponse);
99 // AddIssueComment adds a comment. Needs the issue:write scope.
100 rpc AddIssueComment(AddIssueCommentRequest) returns (AddIssueCommentResponse);
101 // CloseIssue closes an issue. Needs the issue:write scope.
102 rpc CloseIssue(CloseIssueRequest) returns (CloseIssueResponse);
103 // ReopenIssue reopens an issue. Needs the issue:write scope.
104 rpc ReopenIssue(ReopenIssueRequest) returns (ReopenIssueResponse);
105 // ListPendingIssues lists issues awaiting moderation, oldest first. Owner
106 // rights only; anyone else gets NOT_FOUND.
107 rpc ListPendingIssues(ListPendingIssuesRequest) returns (ListPendingIssuesResponse);
108 // ApproveIssue turns a pending issue into an open issue with a new number.
109 // Owner rights only; anyone else gets NOT_FOUND.
110 rpc ApproveIssue(ApproveIssueRequest) returns (ApproveIssueResponse);
111 // RejectIssue discards a pending issue, optionally banning its submitter.
112 // Owner rights only; anyone else gets NOT_FOUND.
113 rpc RejectIssue(RejectIssueRequest) returns (RejectIssueResponse);
114}
115
116// CreateIssueRequest describes the issue to open.
117message CreateIssueRequest {
118 // Repo is the repository name.
119 string repo = 1;
120 // Title is the one-line title. Required.
121 string title = 2;
122 // Body is the optional content.
123 string body = 3;
124}
125
126// CreateIssueResponse holds the new issue.
127message CreateIssueResponse {
128 // Issue is the created issue.
129 Issue issue = 1;
130}
131
132// ListIssuesRequest selects a page of issues.
133message ListIssuesRequest {
134 // Repo is the repository name.
135 string repo = 1;
136 // State restricts the result to one state. ISSUE_STATE_UNSPECIFIED means
137 // every state.
138 IssueState state = 2;
139 // PageSize is the maximum number of issues to return. 0 means the server
140 // default; values above the server maximum are lowered to it.
141 int32 page_size = 3;
142 // PageToken is the next_page_token of a previous response, to continue the
143 // same listing. Empty for the first page. Other fields must be unchanged.
144 string page_token = 4;
145}
146
147// ListIssuesResponse is one page of issues.
148message ListIssuesResponse {
149 // Issues are the issues of this page, highest number first.
150 repeated Issue issues = 1;
151 // NextPageToken is passed as page_token to get the next page. Empty when
152 // there is no next page.
153 string next_page_token = 2;
154}
155
156// GetIssueRequest selects an issue.
157message GetIssueRequest {
158 // Repo is the repository name.
159 string repo = 1;
160 // Number is the issue number.
161 int64 number = 2;
162}
163
164// GetIssueResponse holds an issue with its comments.
165message GetIssueResponse {
166 // Issue is the issue.
167 Issue issue = 1;
168 // Comments are every comment of the issue, oldest first.
169 repeated IssueComment comments = 2;
170}
171
172// AddIssueCommentRequest describes the comment to add.
173message AddIssueCommentRequest {
174 // Repo is the repository name.
175 string repo = 1;
176 // Number is the issue number.
177 int64 number = 2;
178 // Text is the content. Required.
179 string text = 3;
180}
181
182// AddIssueCommentResponse holds the new comment.
183message AddIssueCommentResponse {
184 // Comment is the created comment.
185 IssueComment comment = 1;
186}
187
188// CloseIssueRequest names the issue to close.
189message CloseIssueRequest {
190 // Repo is the repository name.
191 string repo = 1;
192 // Number is the issue number.
193 int64 number = 2;
194}
195
196// CloseIssueResponse holds the issue after closing.
197message CloseIssueResponse {
198 // Issue is the closed issue.
199 Issue issue = 1;
200}
201
202// ReopenIssueRequest names the issue to reopen.
203message ReopenIssueRequest {
204 // Repo is the repository name.
205 string repo = 1;
206 // Number is the issue number.
207 int64 number = 2;
208}
209
210// ReopenIssueResponse holds the issue after reopening.
211message ReopenIssueResponse {
212 // Issue is the reopened issue.
213 Issue issue = 1;
214}
215
216// PendingIssue is an issue awaiting moderation. It has no number yet.
217message PendingIssue {
218 // Id identifies the pending issue. Opaque internal id, not a number.
219 string id = 1;
220 // Repo is the name of the repository.
221 string repo = 2;
222 // Title is the one-line title.
223 string title = 3;
224 // Body is the content. It may be empty.
225 string body = 4;
226 // Author is the optional display name given by the anonymous submitter. It
227 // may be empty or "anonymous", and is not verified: it never proves
228 // identity (a visitor can type "owner"). It becomes Issue.author on approval.
229 string author = 5;
230 // CreatedAt is when the issue was submitted.
231 google.protobuf.Timestamp created_at = 6;
232}
233
234// ListPendingIssuesRequest selects a page of pending issues.
235message ListPendingIssuesRequest {
236 // Repo is the repository name. Empty means every repository.
237 string repo = 1;
238 // PageSize is the maximum number of issues to return. 0 means the server
239 // default; values above the server maximum are lowered to it.
240 int32 page_size = 2;
241 // PageToken is the next_page_token of a previous response, to continue the
242 // same listing. Empty for the first page. Other fields must be unchanged.
243 string page_token = 3;
244}
245
246// ListPendingIssuesResponse is one page of pending issues.
247message ListPendingIssuesResponse {
248 // Issues are the pending issues of this page, oldest first.
249 repeated PendingIssue issues = 1;
250 // NextPageToken is passed as page_token to get the next page. Empty when
251 // there is no next page.
252 string next_page_token = 2;
253}
254
255// ApproveIssueRequest names the pending issue to approve.
256message ApproveIssueRequest {
257 // Repo is the repository name.
258 string repo = 1;
259 // Id is the PendingIssue.id.
260 string id = 2;
261}
262
263// ApproveIssueResponse holds the approved issue.
264message ApproveIssueResponse {
265 // Issue is the approved issue, with its new number and state
266 // ISSUE_STATE_OPEN.
267 Issue issue = 1;
268}
269
270// RejectIssueRequest names the pending issue to reject.
271message RejectIssueRequest {
272 // Repo is the repository name.
273 string repo = 1;
274 // Id is the PendingIssue.id.
275 string id = 2;
276 // Ban also bans the submitter for a while.
277 bool ban = 3;
278}
279
280// RejectIssueResponse is empty: the pending issue is gone.
281message RejectIssueResponse {}