v0.8.0 11411cf

merge_request.proto RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3syntax = "proto3";
4
5package ermite;
6
7import "ermite/git.proto";
8import "ermite/types.proto";
9import "google/protobuf/timestamp.proto";
10
11// MergeRequestState is where a merge request is in its life.
12enum MergeRequestState {
13  // Not set. In ListMergeRequestsRequest.state it means every state. Never
14  // returned by the server.
15  MERGE_REQUEST_STATE_UNSPECIFIED = 0;
16  // The merge request awaits review; it can be commented on, merged or closed.
17  MERGE_REQUEST_STATE_OPEN = 1;
18  // The source branch was merged into the target. Final.
19  MERGE_REQUEST_STATE_MERGED = 2;
20  // The merge request was closed without merging. Final.
21  MERGE_REQUEST_STATE_CLOSED = 3;
22}
23
24// DiffSide is the side of a diff a line comment is attached to.
25enum DiffSide {
26  // Not set. On a Comment it means the comment is general, not attached to a
27  // line. In AddCommentRequest it is valid only for a general comment.
28  DIFF_SIDE_UNSPECIFIED = 0;
29  // The old side: the line is a Line.old_number (a deletion or a context line).
30  DIFF_SIDE_OLD = 1;
31  // The new side: the line is a Line.new_number (an addition or a context
32  // line).
33  DIFF_SIDE_NEW = 2;
34}
35
36// Verdict is the judgement a reviewer gives with a comment.
37enum Verdict {
38  // Not set. The comment carries no verdict. In AddCommentRequest it means a
39  // plain comment.
40  VERDICT_UNSPECIFIED = 0;
41  // The reviewer approves the merge request. The comment is created resolved.
42  VERDICT_APPROVE = 1;
43  // The reviewer asks for changes. The comment starts unresolved.
44  VERDICT_CHANGES_REQUESTED = 2;
45}
46
47// MergeRequest asks to merge one branch of a repository into another branch
48// of the same repository. It is about a branch, not about who wrote it.
49message MergeRequest {
50  // Repo is the name of the repository.
51  string repo = 1;
52  // Number identifies the merge request within its repository, starting at 1
53  // and never reused. It is written "!<number>" in messages and URLs.
54  int64 number = 2;
55  // Title is a one-line plain-text title, at most 120 characters.
56  string title = 3;
57  // Description is a plain-text description, at most 8,000 characters. It may
58  // be empty. Clients show it escaped, with line breaks kept.
59  string description = 4;
60  // SourceBranch is the short name of the branch to merge, for example
61  // "feat/x".
62  string source_branch = 5;
63  // TargetBranch is the short name of the branch to merge into, for example
64  // "main".
65  string target_branch = 6;
66  // State is where the merge request is in its life.
67  MergeRequestState state = 7;
68  // Author names who created the merge request: the label of the token that
69  // was used, "root" for the root token, or "owner" for a web session. It is
70  // informational: labels are not unique and the token may be gone.
71  string author = 8;
72  // CreatedAt is when the merge request was created.
73  google.protobuf.Timestamp created_at = 9;
74  // UpdatedAt is when the merge request last changed: title, description,
75  // state, or a comment added or resolved. Pushes to the source branch do not
76  // change it.
77  google.protobuf.Timestamp updated_at = 10;
78  // HeadId is the id of the commit the source branch points to. While the
79  // merge request is open it is read from Git at every call, so it changes
80  // when the branch is pushed; it is empty if the branch was deleted. Once
81  // merged or closed it is the head at that moment.
82  string head_id = 11;
83  // MergedCommitId is the id of the commit the target branch points to after
84  // the merge: the head for a fast-forward, the new commit for a squash.
85  // Empty unless state is MERGED.
86  string merged_commit_id = 12;
87  // MergeMode is how the merge request was merged. MERGE_MODE_UNSPECIFIED
88  // unless state is MERGED.
89  MergeMode merge_mode = 13;
90}
91
92// Comment is a note on a merge request, either general or attached to a line
93// of its diff.
94message Comment {
95  // Id identifies the comment within its merge request. Opaque.
96  string id = 1;
97  // Author names who wrote the comment, like MergeRequest.author.
98  string author = 2;
99  // Path is the path of the commented file in the diff (the new path, or the
100  // old path of a deleted file). Empty for a general comment.
101  string path = 3;
102  // Line is the 1-based line number on side. 0 for a general comment.
103  int32 line = 4;
104  // Side tells whether line counts on the old or the new side of the diff.
105  // DIFF_SIDE_UNSPECIFIED for a general comment.
106  DiffSide side = 5;
107  // CommitId is the head of the merge request when the comment was written.
108  // When it differs from the current head the line may have moved; clients
109  // may show the comment as outdated.
110  string commit_id = 6;
111  // Text is the Markdown source, at most 8,000 characters. Clients render it
112  // as Markdown without raw HTML; "^<id>" refers to a note of the same merge
113  // request. Empty when deleted is true, and possibly empty for a comment
114  // that carries a verdict.
115  string text = 7;
116  // Resolved is true once the comment was marked resolved.
117  bool resolved = 8;
118  // CreatedAt is when the comment was written.
119  google.protobuf.Timestamp created_at = 9;
120  // ReplyTo is the id of the root comment this comment replies to. Empty for
121  // a root comment. A reply has the path, line, start_line and side of its
122  // root, and its commit_id is the head when the reply was written. Threads
123  // have one level: a reply never has replies.
124  string reply_to = 10;
125  // StartLine is the 1-based first line of a range that ends at line, on the
126  // same side. 0 for a comment on a single line or a general comment.
127  int32 start_line = 11;
128  // Verdict is the judgement given with the comment. Only a root comment has
129  // one; it never changes after creation.
130  Verdict verdict = 12;
131  // EditedAt is when the text was last changed or the comment was deleted.
132  // Unset if it never was.
133  google.protobuf.Timestamp edited_at = 13;
134  // Deleted is true once the author deleted the comment. Its text is then
135  // empty; its id, anchor, replies and verdict remain.
136  bool deleted = 14;
137}
138
139// AuthorVerdict is the current verdict of one author on a merge request: the
140// one given with the author's latest comment that carries a verdict.
141message AuthorVerdict {
142  // Author names who gave the verdict, like Comment.author.
143  string author = 1;
144  // Verdict is the current verdict. Never VERDICT_UNSPECIFIED.
145  Verdict verdict = 2;
146  // CommentId is the id of the comment that carries the verdict.
147  string comment_id = 3;
148  // CommitId is the head of the merge request when the verdict was given.
149  string commit_id = 4;
150  // CreatedAt is when the verdict was given.
151  google.protobuf.Timestamp created_at = 5;
152  // Stale is true for an approval given on a commit that is not the current
153  // head. A request for changes is never stale.
154  bool stale = 6;
155}
156
157// MergeRequestService reviews and merges branches.
158//
159// Every RPC takes the repository name and, except for creation and listing,
160// the merge request number. A repository that does not exist or that the
161// caller cannot read gives not_found; so does an unknown number. Reading
162// (ListMergeRequests, GetMergeRequest) needs the same access as reading the
163// repository: nothing for a public one, the repo:read scope for a private
164// one. Writing needs a scope on the repository, given per RPC; a caller
165// without it gets permission_denied.
166//
167// Text fields follow the same rules everywhere: valid UTF-8, no control
168// characters (except the line break in description and comment text) and no
169// Unicode bidirectional override or isolate characters; title is one line of
170// at most 120 characters, description and comment text at most 8,000
171// characters. A request that breaks a rule is rejected whole with
172// invalid_argument, and the error carries a BadRequest detail naming the
173// fields.
174//
175// Servers that implement this service list "merge_requests" in
176// GetVersionResponse.features.
177service MergeRequestService {
178  // CreateMergeRequest opens a merge request. Needs the mr:write scope. Fails
179  // with invalid_argument if a text rule is broken, if a branch does not exist
180  // or if source and target are the same branch, and with already_exists if an
181  // open merge request already has the same source and target.
182  rpc CreateMergeRequest(CreateMergeRequestRequest) returns (CreateMergeRequestResponse);
183  // ListMergeRequests lists the merge requests of a repository, highest
184  // number (newest) first, optionally restricted to one state. The listed
185  // merge requests carry no diff or comments; head_id is set. Fails with
186  // not_found if the repository does not exist or is not readable.
187  rpc ListMergeRequests(ListMergeRequestsRequest) returns (ListMergeRequestsResponse);
188  // GetMergeRequest returns one merge request with its commits, its diff and
189  // its comments. The diff compares the target with the head (what the merge
190  // would bring: "target...head"), or, with since_last_read, the head the
191  // caller last marked read with the current head. Fails with not_found if
192  // the repository or the number is unknown.
193  rpc GetMergeRequest(GetMergeRequestRequest) returns (GetMergeRequestResponse);
194  // AddComment adds a general comment, a comment on a line or a range of
195  // lines of the diff, or a reply to a root comment. Needs the mr:write
196  // scope; setting a verdict also needs the mr:review scope (permission_denied
197  // without it). Fails with invalid_argument if the text breaks a rule (it may
198  // be empty only with a verdict), if path, line, start_line and side do not
199  // designate lines of the current diff of the merge request, if reply_to is
200  // not the id of a root comment that is not deleted, if a reply sets path,
201  // line, start_line, side or verdict, or if a verdict is set on a reply; and
202  // with failed_precondition if the merge request is not open. A comment with
203  // VERDICT_APPROVE is created resolved.
204  rpc AddComment(AddCommentRequest) returns (AddCommentResponse);
205  // EditComment replaces the text of a comment. Needs the mr:write scope, and
206  // only the author of the comment can edit it (permission_denied
207  // otherwise). Fails with invalid_argument if the text breaks a rule (it may
208  // be empty only for a comment with a verdict), with not_found if the comment
209  // is unknown, and with failed_precondition if the merge request is not open
210  // or the comment was deleted. Sending the current text succeeds and changes
211  // nothing.
212  rpc EditComment(EditCommentRequest) returns (EditCommentResponse);
213  // DeleteComment deletes a comment: its text is emptied and deleted is set,
214  // while its id, anchor, replies and verdict remain. Needs the mr:write
215  // scope, and only the author of the comment can delete it
216  // (permission_denied otherwise). Fails with not_found if the comment is
217  // unknown and with failed_precondition if the merge request is not open.
218  // Deleting a comment already deleted succeeds and changes nothing.
219  rpc DeleteComment(DeleteCommentRequest) returns (DeleteCommentResponse);
220  // ResolveComment marks a thread resolved or unresolved. Needs the mr:write
221  // scope. Resolution belongs to the root comment: on a reply it fails with
222  // invalid_argument. Fails with not_found if the comment is unknown and with
223  // failed_precondition if the merge request is not open. Setting the state
224  // the comment already has succeeds and changes nothing.
225  rpc ResolveComment(ResolveCommentRequest) returns (ResolveCommentResponse);
226  // CloseMergeRequest closes an open merge request without merging it. Needs
227  // the mr:write scope. Fails with failed_precondition if the merge request
228  // is not open. A closed merge request cannot be reopened: open a new one.
229  rpc CloseMergeRequest(CloseMergeRequestRequest) returns (CloseMergeRequestResponse);
230  // MergeMergeRequest merges an open merge request. Needs the mr:merge scope.
231  // The caller passes the head it reviewed: the server merges only if the
232  // source branch still points to it, so a push between review and merge is
233  // never merged unseen. Fails with invalid_argument if head_id is empty or
234  // not a commit id, and with failed_precondition if the merge request is not
235  // open, if the source branch no longer points to head_id ("branch moved,
236  // read again"), if the target is not an ancestor of the head (rebase and
237  // push again), if the mode is not allowed by RepoSettings, or if a check
238  // fails and RepoSettings.failing_checks_block is set. Merges of one
239  // repository run one at a time. Repeating a call that succeeded fails with
240  // failed_precondition (not open). On success the server publishes
241  // MergeRequestMerged then Pushed for the target branch.
242  rpc MergeMergeRequest(MergeMergeRequestRequest) returns (MergeMergeRequestResponse);
243  // MarkRead records the head the caller has reviewed, for the since_last_read
244  // option of GetMergeRequest. There is one read position per merge request,
245  // the reviewer's. Needs the mr:write scope. Marking a commit that does not
246  // exist in the repository is invalid_argument.
247  rpc MarkRead(MarkReadRequest) returns (MarkReadResponse);
248}
249
250// CreateMergeRequestRequest describes the merge request to open.
251message CreateMergeRequestRequest {
252  // Repo is the repository name.
253  string repo = 1;
254  // Title is the one-line title. Required.
255  string title = 2;
256  // Description is the optional description.
257  string description = 3;
258  // SourceBranch is the short name of the branch to merge. Required; the
259  // branch must exist.
260  string source_branch = 4;
261  // TargetBranch is the short name of the branch to merge into. Empty means
262  // the default branch of the repository. The branch must exist and differ
263  // from source_branch.
264  string target_branch = 5;
265}
266
267// CreateMergeRequestResponse holds the new merge request.
268message CreateMergeRequestResponse {
269  // MergeRequest is the created merge request.
270  MergeRequest merge_request = 1;
271}
272
273// ListMergeRequestsRequest selects a page of merge requests.
274message ListMergeRequestsRequest {
275  // Repo is the repository name.
276  string repo = 1;
277  // State restricts the result to one state. MERGE_REQUEST_STATE_UNSPECIFIED
278  // means every state.
279  MergeRequestState state = 2;
280  // PageSize is the maximum number of merge requests to return. 0 means the
281  // server default; values above the server maximum are lowered to it.
282  int32 page_size = 3;
283  // PageToken is the next_page_token of a previous response, to continue the
284  // same listing. Empty for the first page. Other fields must be unchanged.
285  string page_token = 4;
286}
287
288// ListMergeRequestsResponse is one page of merge requests.
289message ListMergeRequestsResponse {
290  // MergeRequests are the merge requests of this page, highest number first.
291  repeated MergeRequest merge_requests = 1;
292  // NextPageToken is passed as page_token to get the next page. Empty when
293  // there is no next page.
294  string next_page_token = 2;
295}
296
297// GetMergeRequestRequest selects a merge request.
298message GetMergeRequestRequest {
299  // Repo is the repository name.
300  string repo = 1;
301  // Number is the merge request number.
302  int64 number = 2;
303  // SinceLastRead asks for the diff between the head recorded by MarkRead and
304  // the current head instead of the diff against the target. It works after a
305  // force-push as long as the recorded commit still exists in the repository.
306  // When nothing was marked read, or the recorded commit is gone, the response
307  // holds the diff against the target and says so in last_read_id and
308  // last_read_lost.
309  bool since_last_read = 3;
310}
311
312// GetMergeRequestResponse holds a merge request with its review data.
313message GetMergeRequestResponse {
314  // MergeRequest is the merge request.
315  MergeRequest merge_request = 1;
316  // Commits are the commits of the head that are not in the target
317  // ("target..head"), newest first. At most 100 are returned (a server limit
318  // that may change; rely on commits_truncated, not on the number). Empty when
319  // the source branch was deleted.
320  repeated Commit commits = 2;
321  // CommitsTruncated is true when the branch has more commits than commits
322  // holds.
323  bool commits_truncated = 3;
324  // DiffBaseId is the id of the commit the diff compares from: the merge base
325  // of the target and the head, or the last read head when since_last_read
326  // applied. Empty when the source branch was deleted; diff is then empty.
327  string diff_base_id = 4;
328  // Stats are the totals of the diff, including files that it omits or
329  // truncates.
330  DiffStats stats = 5;
331  // Diff is the structured diff from diff_base_id to the head, with the same
332  // limits and truncated flags as GetCommitResponse.diff.
333  Diff diff = 6;
334  // Comments are every comment of the merge request, oldest first.
335  repeated Comment comments = 7;
336  // LastReadId is the head recorded by MarkRead, whether or not
337  // since_last_read was set. Empty when nothing was marked read.
338  string last_read_id = 8;
339  // LastReadLost is true when since_last_read was set, a head was recorded,
340  // but that commit no longer exists in the repository: the diff is then the
341  // diff against the target. A client should tell the reader to review the
342  // whole change again.
343  bool last_read_lost = 9;
344  // Verdicts are the current verdicts, one per author who gave one, ordered
345  // by the comment that carries them, oldest first.
346  repeated AuthorVerdict verdicts = 10;
347}
348
349// AddCommentRequest describes the comment to add.
350message AddCommentRequest {
351  // Repo is the repository name.
352  string repo = 1;
353  // Number is the merge request number.
354  int64 number = 2;
355  // Path is the file the comment is attached to, as given by the diff of the
356  // merge request: FileDiff.new_path, or old_path for a deleted file. Empty
357  // for a general comment; then line must be 0 and side unspecified.
358  string path = 3;
359  // Line is the 1-based line number on side. It must be the old_number or
360  // new_number of a Line of a hunk of the file; a line outside the hunks is
361  // invalid_argument. 0 for a general comment.
362  int32 line = 4;
363  // Side is the side line counts on. Required when path is set.
364  DiffSide side = 5;
365  // Text is the Markdown source. Required, except when verdict is set.
366  string text = 6;
367  // ReplyTo is the id of the root comment to reply to. Empty for a new root
368  // comment. A reply takes the anchor of its root: path, line, start_line,
369  // side and verdict must then be unset.
370  string reply_to = 7;
371  // StartLine is the 1-based first line of a range ending at line. 0 for a
372  // single line. Needs path; it must be lower than line, and both ends must
373  // be lines of the diff on side.
374  int32 start_line = 8;
375  // Verdict is the judgement to give. Needs the mr:review scope and a root
376  // comment. VERDICT_UNSPECIFIED for a plain comment.
377  Verdict verdict = 9;
378}
379
380// AddCommentResponse holds the new comment.
381message AddCommentResponse {
382  // Comment is the created comment.
383  Comment comment = 1;
384}
385
386// EditCommentRequest describes the new text of a comment.
387message EditCommentRequest {
388  // Repo is the repository name.
389  string repo = 1;
390  // Number is the merge request number.
391  int64 number = 2;
392  // CommentId is the Comment.id to edit.
393  string comment_id = 3;
394  // Text is the new Markdown source. Required, except for a comment that
395  // carries a verdict.
396  string text = 4;
397}
398
399// EditCommentResponse holds the comment after the edit.
400message EditCommentResponse {
401  // Comment is the updated comment.
402  Comment comment = 1;
403}
404
405// DeleteCommentRequest names the comment to delete.
406message DeleteCommentRequest {
407  // Repo is the repository name.
408  string repo = 1;
409  // Number is the merge request number.
410  int64 number = 2;
411  // CommentId is the Comment.id to delete.
412  string comment_id = 3;
413}
414
415// DeleteCommentResponse holds the comment after the deletion.
416message DeleteCommentResponse {
417  // Comment is the deleted comment.
418  Comment comment = 1;
419}
420
421// ResolveCommentRequest changes the resolved state of a comment.
422message ResolveCommentRequest {
423  // Repo is the repository name.
424  string repo = 1;
425  // Number is the merge request number.
426  int64 number = 2;
427  // CommentId is the Comment.id to change.
428  string comment_id = 3;
429  // Resolved is the new state: true to resolve, false to unresolve.
430  bool resolved = 4;
431}
432
433// ResolveCommentResponse holds the comment after the change.
434message ResolveCommentResponse {
435  // Comment is the updated comment.
436  Comment comment = 1;
437}
438
439// CloseMergeRequestRequest names the merge request to close.
440message CloseMergeRequestRequest {
441  // Repo is the repository name.
442  string repo = 1;
443  // Number is the merge request number.
444  int64 number = 2;
445}
446
447// CloseMergeRequestResponse holds the merge request after closing.
448message CloseMergeRequestResponse {
449  // MergeRequest is the closed merge request.
450  MergeRequest merge_request = 1;
451}
452
453// MergeMergeRequestRequest describes the merge to perform.
454message MergeMergeRequestRequest {
455  // Repo is the repository name.
456  string repo = 1;
457  // Number is the merge request number.
458  int64 number = 2;
459  // Mode is how to merge. MERGE_MODE_UNSPECIFIED means fast-forward. The mode
460  // must be in RepoSettings.allowed_merge_modes of the repository.
461  MergeMode mode = 3;
462  // HeadId is the full id of the commit the caller reviewed, that is the
463  // MergeRequest.head_id it was shown. Required. The merge happens only if the
464  // source branch still points to it.
465  string head_id = 4;
466  // DeleteSourceBranch deletes the source branch after the merge. The merge
467  // is refused before anything changes when the source branch is the default
468  // branch of the repository or the source or target of another open merge
469  // request. Servers without the "merge_requests.delete_branch" feature ignore
470  // it.
471  bool delete_source_branch = 5;
472}
473
474// MergeMergeRequestResponse holds the merged merge request.
475message MergeMergeRequestResponse {
476  // MergeRequest is the merge request after the merge: state MERGED,
477  // merged_commit_id set to the new tip of the target branch and merge_mode
478  // set to the mode used.
479  MergeRequest merge_request = 1;
480  // SourceBranchDeleted is true when delete_source_branch was set and the
481  // branch is gone. It is false when the deletion failed after the merge (the
482  // branch moved in between, say): the merge stands and the branch is kept.
483  bool source_branch_deleted = 2;
484}
485
486// MarkReadRequest records a read position.
487message MarkReadRequest {
488  // Repo is the repository name.
489  string repo = 1;
490  // Number is the merge request number.
491  int64 number = 2;
492  // HeadId is the full id of the commit the caller has reviewed, usually the
493  // MergeRequest.head_id it was shown. Empty means the current head of the
494  // source branch.
495  string head_id = 3;
496}
497
498// MarkReadResponse is empty.
499message MarkReadResponse {}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 18

↑↓ moveenter openesc close