1// SPDX-License-Identifier: MIT
2
3syntax = "proto3";
4
5package ermite;
6
7import "ermite/merge_request.proto";
8import "ermite/repo.proto";
9import "ermite/run.proto";
10import "google/protobuf/timestamp.proto";
11
12// EventService streams what happens on the forge.
13service EventService {
14 // Watch streams events until the client cancels the call or the server shuts
15 // down. Events are filtered by the caller's access: events of a private
16 // repository are only sent to callers that may read it.
17 //
18 // The events are repo_created, repo_updated, repo_deleted, pushed, gap and,
19 // for merge requests, merge_request_opened, merge_request_merged,
20 // merge_request_closed and comment_added. Each one is delivered on the
21 // "repo:<name>" topic of its repository and on "home", subject to the
22 // visibility of the repository.
23 //
24 // Servers with the feature "ci.runs" also publish run_updated and
25 // job_updated, only on the "repo:<name>" topic of their repository (never on
26 // "home"), subject to the same visibility. They carry the state after the
27 // change and are published when a run or a job is created, changes status
28 // or conclusion, or when one of its steps starts or ends (never per log
29 // line: follow a log with RunService.GetJobLog). The order of these events
30 // is not guaranteed, between jobs and runs or between two updates of the same
31 // one: a client keeps the copy with the higher Run.version or
32 // RunJob.version and drops the other. There is no event for a change of title or
33 // description, nor for a resolved comment: after a gap, or to see such
34 // changes, clients read the merge request again. A merge publishes
35 // merge_request_merged, then pushed for the target branch.
36 //
37 // The server keeps a bounded buffer of recent events. With resume_after set,
38 // buffered events after that id are replayed first, then live events follow.
39 // When resume_after is no longer buffered (or unknown), the stream begins
40 // with a Gap event, then continues with the oldest buffered event: the client
41 // must reload its state. Without resume_after, only new events are sent.
42 //
43 // The access of the caller is checked again for every event: the stream ends
44 // with unauthenticated when the token was revoked or has expired (the server
45 // may take a few seconds to notice). A repository that becomes private
46 // sends one last repo_updated to the callers who could read it before, with
47 // the new visibility and nothing else about it; no later event of it
48 // reaches them. The server limits the watchers: more than 64 topics is
49 // invalid_argument, and too many concurrent streams, in total or from one
50 // client, is resource_exhausted.
51 rpc Watch(WatchRequest) returns (stream WatchResponse);
52}
53
54// WatchRequest selects the events to receive.
55message WatchRequest {
56 // Topics are the subjects to follow: "home" for every repository visible to
57 // the caller, or "repo:<name>" for one repository. Empty means "home".
58 // Unknown topics are invalid_argument. A "repo:<name>" topic for a repository
59 // that does not exist or is not visible is not_found.
60 repeated string topics = 1;
61 // ResumeAfter is the Event.id of the last event the client has seen. Empty
62 // to receive only new events.
63 string resume_after = 2;
64}
65
66// WatchResponse carries one event of the stream.
67message WatchResponse {
68 // Event is the event.
69 Event event = 1;
70}
71
72// Event is something that happened on the forge.
73message Event {
74 // Id identifies the event and is passed as resume_after to resume a stream.
75 // It is opaque and only comparable for equality; clients must not parse it.
76 // Empty on a Gap event.
77 string id = 1;
78 // Time is when the event happened.
79 google.protobuf.Timestamp time = 2;
80 // Kind is the type and payload of the event. New kinds may be added; clients
81 // must ignore kinds they do not know.
82 oneof kind {
83 // RepoCreated: a repository was created.
84 RepoCreated repo_created = 3;
85 // RepoUpdated: repository metadata changed.
86 RepoUpdated repo_updated = 4;
87 // RepoDeleted: a repository was deleted.
88 RepoDeleted repo_deleted = 5;
89 // Pushed: refs of a repository were updated by a push.
90 Pushed pushed = 6;
91 // Gap: events were lost, reload state.
92 Gap gap = 7;
93 // MergeRequestOpened: a merge request was opened.
94 MergeRequestOpened merge_request_opened = 8;
95 // MergeRequestMerged: a merge request was merged.
96 MergeRequestMerged merge_request_merged = 9;
97 // MergeRequestClosed: a merge request was closed without merging.
98 MergeRequestClosed merge_request_closed = 10;
99 // CommentAdded: a comment was added to a merge request.
100 CommentAdded comment_added = 11;
101 // RunUpdated: a CI run was created or changed.
102 RunUpdated run_updated = 12;
103 // JobUpdated: a CI job was created or changed.
104 JobUpdated job_updated = 13;
105 }
106}
107
108// RepoCreated reports a new repository.
109message RepoCreated {
110 // Repo is the new repository.
111 Repo repo = 1;
112}
113
114// RepoUpdated reports a metadata change.
115message RepoUpdated {
116 // Repo is the repository after the change.
117 Repo repo = 1;
118}
119
120// RepoDeleted reports a deleted repository.
121message RepoDeleted {
122 // Repo is the name of the deleted repository.
123 string repo = 1;
124}
125
126// Pushed reports the ref updates of one push.
127message Pushed {
128 // Repo is the name of the repository.
129 string repo = 1;
130 // RefUpdates are the refs changed by the push.
131 repeated RefUpdate ref_updates = 2;
132}
133
134// RefUpdate is the change of one ref.
135message RefUpdate {
136 // Ref is the full ref name, for example "refs/heads/main".
137 string ref = 1;
138 // OldId is the object id before the update. Empty when the ref was created.
139 string old_id = 2;
140 // NewId is the object id after the update. Empty when the ref was deleted.
141 string new_id = 3;
142}
143
144// MergeRequestOpened reports a new merge request.
145message MergeRequestOpened {
146 // MergeRequest is the new merge request.
147 MergeRequest merge_request = 1;
148}
149
150// MergeRequestMerged reports a merged merge request. It is published before
151// the Pushed event of the target branch.
152message MergeRequestMerged {
153 // MergeRequest is the merge request after the merge.
154 MergeRequest merge_request = 1;
155}
156
157// MergeRequestClosed reports a merge request closed without merging.
158message MergeRequestClosed {
159 // MergeRequest is the merge request after closing.
160 MergeRequest merge_request = 1;
161}
162
163// CommentAdded reports a new comment on a merge request.
164message CommentAdded {
165 // Repo is the name of the repository.
166 string repo = 1;
167 // Number is the number of the merge request.
168 int64 number = 2;
169 // Comment is the new comment.
170 Comment comment = 3;
171}
172
173// Gap tells the client that events were lost: the requested resume point is
174// older than the server's buffer. It has no fields. The client should reload
175// the state it displays (repositories, refs, merge requests and their
176// comments, CI runs and their jobs) and carry on with the next events.
177message Gap {}
178
179// RunUpdated reports a CI run that was created or whose status, conclusion or
180// timestamps changed. It is delivered on the "repo:<name>" topic only.
181message RunUpdated {
182 // Run is the run after the change, as of its latest attempt, without jobs.
183 Run run = 1;
184}
185
186// JobUpdated reports a CI job that was created or whose status, conclusion,
187// runner or steps changed. It is delivered on the "repo:<name>" topic only.
188message JobUpdated {
189 // Job is the job after the change, with its steps.
190 RunJob job = 1;
191}