v0.1.0 4db3b8b

run.proto RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3syntax = "proto3";
4
5package ermite;
6
7import "ermite/runner.proto";
8import "google/protobuf/timestamp.proto";
9
10// Run is one execution of one workflow file for one event, like a GitHub
11// workflow run. A re-run keeps the run and adds an attempt.
12message Run {
13  // Repo is the name of the repository.
14  string repo = 1;
15  // Id identifies the run on the whole server: it is the "github.run_id".
16  // Increasing, never reused.
17  int64 id = 2;
18  // Number counts the runs of the same workflow file in the repository,
19  // starting at 1, never reused: it is the "github.run_number". It does not
20  // change on a re-run.
21  int64 number = 3;
22  // Attempt is the attempt this message describes: 1 for the first, one more
23  // after each RerunRun. ListRuns and events describe the latest attempt;
24  // GetRun can ask for another one.
25  int32 attempt = 4;
26  // WorkflowPath is the path of the workflow file at sha, for example
27  // ".github/workflows/ci.yml".
28  string workflow_path = 5;
29  // WorkflowName is the "name" of the workflow, or workflow_path when it has
30  // none (as GitHub does). It is the "github.workflow" of the run and the
31  // workflow name of its checks. See name for the name of the run itself.
32  string workflow_name = 6;
33  // Title is GitHub's display title, at most 256 characters: the evaluated
34  // "run-name" of the workflow when it has one, else for a push to a branch
35  // the first line of the message of the commit sha, and for a push of a tag
36  // the name of the workflow registered for workflow_path (the "name" of that
37  // file on the default branch, else workflow_name).
38  string title = 7;
39  // Event is the event that triggered the run, in GitHub's name: "push" (the
40  // only one for now; push to a branch or a tag, and merge of a merge
41  // request). New values may be added; clients show the ones they do not
42  // know as they are.
43  string event = 8;
44  // Ref is the full ref name that was pushed, for example "refs/heads/main"
45  // or "refs/tags/v1.0.0".
46  string ref = 9;
47  // Sha is the full id of the commit the run is for.
48  string sha = 10;
49  // Actor names who triggered the run: the label of the token that pushed, or
50  // "root", or "owner" (a web session, a merge of the web UI), as
51  // MergeRequest.author. It is informational.
52  string actor = 11;
53  // Status is where this attempt is: QUEUED until a job starts, IN_PROGRESS
54  // while jobs run or wait, COMPLETED when every job is over.
55  CiStatus status = 12;
56  // Conclusion is how this attempt ended, from its jobs' conclusions like
57  // GitHub: CANCELLED if it was cancelled, else FAILURE if a job failed or
58  // timed out, else SUCCESS (also when jobs were skipped). Unset until
59  // status is COMPLETED.
60  CiConclusion conclusion = 13;
61  // Error is set when the run failed without running a job because the
62  // workflow could not be used: an invalid workflow file (the run then has
63  // no jobs and conclusion FAILURE), as GitHub's "Invalid workflow file".
64  // It holds the errors with their positions, one per line, at most 8 KiB.
65  // Empty otherwise.
66  string error = 14;
67  // CreatedAt is when this attempt was created: for attempt 1 when the
68  // trigger was planned, for later ones when RerunRun was called.
69  google.protobuf.Timestamp created_at = 15;
70  // StartedAt is when the first job of this attempt was given to a runner.
71  // Unset until then.
72  google.protobuf.Timestamp started_at = 16;
73  // CompletedAt is when this attempt completed. Unset until then.
74  google.protobuf.Timestamp completed_at = 17;
75  // Version counts the changes of this run on the server: it grows by at least
76  // one at every change and never goes back, also across attempts. Events are
77  // not delivered in order, and a client that holds two copies of a run keeps
78  // the one with the higher version and drops the other.
79  int64 version = 18;
80  // Name is the name of the run, GitHub's "name" of a workflow run: the
81  // evaluated "run-name" of the workflow when it has one, else the same value
82  // as workflow_name. It is what GitHub lists as the run's name, whereas
83  // workflow_name stays the name of the workflow ("github.workflow") even when
84  // the workflow has a "run-name". A run stored before this field existed
85  // reads as workflow_name.
86  string name = 19;
87}
88
89// RunJob is a job of a run as people see it: the state of one job instance
90// (one matrix combination is one job) in one attempt. It is not Job, which is
91// what a runner receives.
92message RunJob {
93  // Id is the Job.job_id. It is the same in every attempt.
94  string id = 1;
95  // RunId is the run the job belongs to.
96  int64 run_id = 2;
97  // Attempt is the attempt of the run in which this job executed. It is lower
98  // than the attempt of the run when the job was kept from an earlier attempt
99  // by a re-run of the failed jobs only; the log and steps are then those of
100  // that earlier attempt. Pass it to GetJob and GetJobLog.
101  int32 attempt = 3;
102  // Repo is the name of the repository.
103  string repo = 4;
104  // Key is the key of the job under "jobs:" in the workflow (the
105  // "github.job"). Matrix instances of one job share it.
106  string key = 5;
107  // Name is the display name of the job, evaluated, with the matrix suffix as
108  // GitHub names them, for example "build (linux, 1.27)". It is also the
109  // name of the job's check.
110  string name = 6;
111  // Status is where the job is. A job waits QUEUED for a runner and for the
112  // jobs it needs.
113  CiStatus status = 7;
114  // Conclusion is how the job ended. Unset until status is COMPLETED.
115  CiConclusion conclusion = 8;
116  // Error explains a FAILURE, CANCELLED or TIMED_OUT that no step explains, in
117  // GitHub's words where it has them: the runner was lost ("The self-hosted
118  // runner: <name> lost communication with the server..."), it received a
119  // shutdown signal, no runner took the job within 24 hours, the log limit
120  // was reached, the workflow uses a feature that is not supported yet
121  // ("not supported yet: <feature>"). At most 4 KiB. Empty otherwise.
122  string error = 9;
123  // Labels are the runs-on labels of the job, evaluated. Empty while the job
124  // is not planned yet.
125  repeated string labels = 10;
126  // Needs are the keys of the jobs this job needs, for drawing the graph.
127  repeated string needs = 11;
128  // RunnerId is the id of the runner that executed or is executing the job.
129  // Empty while queued, and when the runner has since been removed (runner_name
130  // and isolation are kept).
131  string runner_id = 12;
132  // RunnerName is the name of that runner. Empty while queued.
133  string runner_name = 13;
134  // Isolation is how that runner isolated the job. UNSPECIFIED while queued.
135  RunnerIsolation isolation = 14;
136  // Steps are the steps reported so far, ordered by number, including the
137  // implicit "Set up job" and "Complete job". Empty while queued. Always
138  // set, including in JobUpdated events.
139  repeated Step steps = 15;
140  // CreatedAt is when the job was created (planned).
141  google.protobuf.Timestamp created_at = 16;
142  // StartedAt is when the job was given to a runner. Unset until then.
143  google.protobuf.Timestamp started_at = 17;
144  // CompletedAt is when the job completed. Unset until then.
145  google.protobuf.Timestamp completed_at = 18;
146  // Version counts the changes of this job on the server (status, conclusion,
147  // runner, steps, with any attempt): it grows by at least one at every change
148  // and never goes back. A client that holds two copies of a job keeps the
149  // one with the higher version and drops the other, as for Run.version.
150  int64 version = 19;
151}
152
153// Step is one step of a job, with where its lines are in the job log.
154message Step {
155  // Number is the 1-based number of the step in the job, the one the runner
156  // uses in UpdateJob and AppendLog.
157  int32 number = 1;
158  // Name is the display name of the step.
159  string name = 2;
160  // State is where the step is.
161  StepState state = 3;
162  // Conclusion is how the step ended. Unset until state is COMPLETED.
163  CiConclusion conclusion = 4;
164  // StartedAt is when the step started. Unset while PENDING.
165  google.protobuf.Timestamp started_at = 5;
166  // CompletedAt is when the step ended. Unset until COMPLETED.
167  google.protobuf.Timestamp completed_at = 6;
168  // LogStart is the number of the first line of the step in the job log (the
169  // offset of GetJobLogRequest and AppendLogRequest), counted from 0.
170  int64 log_start = 7;
171  // LogEnd is the number of the line after the last one of the step. For an
172  // IN_PROGRESS step it is the number of lines held at the time of the
173  // call and grows; for a step without a line it equals log_start.
174  int64 log_end = 8;
175}
176
177// Check is the result of one job on one commit, the unit shown next to a
178// commit or a merge request and counted by the merge rules. There is one per
179// job instance, named like GitHub's checks.
180message Check {
181  // Id identifies the check. It is opaque and stable across attempts.
182  string id = 1;
183  // Repo is the name of the repository.
184  string repo = 2;
185  // Sha is the full id of the commit.
186  string sha = 3;
187  // Name is the name of the check: the RunJob.name of the job.
188  string name = 4;
189  // Status is where the check is.
190  CiStatus status = 5;
191  // Conclusion is how the check ended. Unset until status is COMPLETED. The
192  // value "stale" of GitHub is never used.
193  CiConclusion conclusion = 6;
194  // RunId is the run of the job.
195  int64 run_id = 7;
196  // JobId is the RunJob.id of the job, to open its page and log.
197  string job_id = 8;
198  // Attempt is the attempt the check describes: the latest attempt of the run.
199  int32 attempt = 9;
200  // WorkflowName is the Run.workflow_name of the run.
201  string workflow_name = 10;
202  // StartedAt is when the job was given to a runner. Unset while queued.
203  google.protobuf.Timestamp started_at = 11;
204  // CompletedAt is when the job completed. Unset until then.
205  google.protobuf.Timestamp completed_at = 12;
206}
207
208// Runner is a registered CI runner. It never contains the runner token nor its
209// hash.
210message Runner {
211  // Id identifies the runner in RemoveRunner. It is not a secret.
212  string id = 1;
213  // Name is the unique name chosen at registration.
214  string name = 2;
215  // Labels are all the labels the runner can match: the ones chosen at
216  // registration plus the implicit ones ("self-hosted", the os and the arch),
217  // lowercase, sorted.
218  repeated string labels = 3;
219  // Isolation is how the runner isolates jobs.
220  RunnerIsolation isolation = 4;
221  // Version is the version of the runner software.
222  string version = 5;
223  // Arch is "x64" or "arm64".
224  string arch = 6;
225  // Os is "linux".
226  string os = 7;
227  // RegisteredAt is when the runner was registered.
228  google.protobuf.Timestamp registered_at = 8;
229  // LastSeen is when the server last heard from the runner: a FetchJob poll or
230  // a heartbeat of one of its jobs. Unset if never. It may lag behind the real
231  // time by a short delay. A runner not seen for more than about 2 minutes is
232  // offline.
233  google.protobuf.Timestamp last_seen = 9;
234  // Busy is true while the runner has a job in progress.
235  bool busy = 10;
236}
237
238// RunService reads and controls CI runs, like `gh run` does on GitHub. It is for
239// owners and their tools; runners use RunnerService.
240//
241// Runs, jobs, checks and logs belong to a repository, and reading them needs
242// the same access as reading it: nothing for a public repository, the
243// repo:read scope for a private one. A repository that does not exist or that
244// the caller cannot read gives not_found; so does a run or a job that belongs
245// to another repository than the one named (ids are global but are always
246// checked against the repository). Cancelling and re-running need the ci:write
247// scope on the repository (a token restricted to other repositories gets
248// permission_denied). The runner RPCs (ListRunners, RemoveRunner) are not about
249// a repository and need the runner:register scope on a token that is not
250// restricted to repositories, or the root token. A caller without the needed
251// scope gets permission_denied.
252//
253// Page sizes and page tokens work as in the other services: page_size 0 is the
254// server default, larger values are lowered to the server maximum, and a
255// page_token is the next_page_token of a previous response for the same
256// request (other fields must be unchanged).
257//
258// Servers that implement the runs side (every RPC but ListRunners and
259// RemoveRunner) list "ci.runs" in GetVersionResponse.features; those that
260// implement the runners side list "ci.runners", as RunnerService does. A server
261// that honours the filters of ListRunsRequest also lists "ci.runs.filters".
262service RunService {
263  // ListRuns lists the runs of a repository, highest id (newest) first. Each
264  // run is described by its latest attempt. The filters narrow the result; a
265  // server without the feature "ci.runs.filters" ignores them and returns
266  // every run, so a client that needs them checks the feature. Fails with
267  // invalid_argument if a filter is malformed.
268  rpc ListRuns(ListRunsRequest) returns (ListRunsResponse);
269  // GetRun returns a run with its jobs and their steps, for the latest attempt
270  // or for the one asked. Fails with not_found if the run or the attempt does
271  // not exist.
272  rpc GetRun(GetRunRequest) returns (GetRunResponse);
273  // GetJob returns one job with its steps. Fails with not_found if the job
274  // or the attempt does not exist.
275  rpc GetJob(GetJobRequest) returns (GetJobResponse);
276  // GetJobLog streams the lines of the log of a job, from a line number. The
277  // server sends them in order in messages of at most 1,000 lines and 64 KiB of
278  // text each.
279  //
280  // Without follow, the stream ends after the last line stored when the call
281  // was made. With follow, it goes on as lines arrive, with at most 1 second of
282  // delay after the runner's AppendLog, and ends without error once the job has
283  // completed and all its lines were sent; on a completed job follow changes
284  // nothing. A client that loses the stream calls again with the offset after
285  // the last line it received. The client may cancel at any time.
286  //
287  // Fails with not_found if the job, the attempt or its log does not exist (the
288  // log is removed by the retention sweep, and a queued job has none: with
289  // follow, the call waits for the first line instead), with out_of_range if
290  // offset is beyond the end of the log of a job without follow, and with
291  // resource_exhausted when there are too many concurrent log streams, in
292  // total or from one client. Like Watch, a stream ends with unauthenticated
293  // when the token was revoked or expired.
294  rpc GetJobLog(GetJobLogRequest) returns (stream GetJobLogResponse);
295  // CancelRun asks to cancel the latest attempt of a run. Needs the ci:write
296  // scope. Jobs that have not started are cancelled at once; jobs in progress
297  // get a CANCEL_REASON_USER request through WatchJob, and the run completes
298  // when they have ended, so the returned run may still be IN_PROGRESS.
299  // Cancelling a run that already has a cancellation requested succeeds and
300  // changes nothing. Fails with failed_precondition if the run has completed.
301  rpc CancelRun(CancelRunRequest) returns (CancelRunResponse);
302  // RerunRun starts a new attempt of a completed run: same run id and number,
303  // attempt + 1, same commit and same workflow file as at the original run (the
304  // file of the repository is not read again). Needs the ci:write scope. Fails
305  // with failed_precondition if the latest attempt has not completed, or if
306  // failed_only is set and no job failed. The new attempt is returned QUEUED.
307  rpc RerunRun(RerunRunRequest) returns (RerunRunResponse);
308  // ListChecks lists the checks of a commit: for each job of each run on that
309  // sha, the one of the latest attempt, ordered by creation time then name.
310  // A commit without a run has no check: the list is empty, which is not an
311  // error, and the server does not verify that the commit exists. Returns at
312  // most 1,000 checks (truncated tells).
313  rpc ListChecks(ListChecksRequest) returns (ListChecksResponse);
314  // ListRunners lists the registered runners, ordered by name. Needs the
315  // runner:register scope.
316  rpc ListRunners(ListRunnersRequest) returns (ListRunnersResponse);
317  // RemoveRunner removes a runner: its runner token stops working at once (a
318  // FetchJob in progress ends with unauthenticated) and it no longer gets
319  // jobs. A job it is running is not affected: it ends normally, or fails as
320  // a lost runner without heartbeats. Needs the runner:register scope. Fails
321  // with not_found if the id is unknown.
322  rpc RemoveRunner(RemoveRunnerRequest) returns (RemoveRunnerResponse);
323}
324
325// ListRunsRequest selects a page of runs.
326message ListRunsRequest {
327  // Repo is the repository name.
328  string repo = 1;
329  // PageSize is the maximum number of runs to return.
330  int32 page_size = 2;
331  // PageToken is the next_page_token of a previous response. Empty for the
332  // first page.
333  string page_token = 3;
334  // Workflow restricts the result to one workflow file: its path
335  // (".github/workflows/ci.yml") or its file name ("ci.yml"). Empty means
336  // every workflow. Ignored by servers without "ci.runs.filters".
337  string workflow = 4;
338  // Branch restricts the result to the runs whose ref is this branch, by
339  // short name ("main"). Empty means every ref. Ignored by servers without
340  // "ci.runs.filters".
341  string branch = 5;
342  // Status restricts the result to the runs whose latest attempt has this
343  // status. CI_STATUS_UNSPECIFIED means every status. Ignored by servers
344  // without "ci.runs.filters".
345  CiStatus status = 6;
346}
347
348// ListRunsResponse is one page of runs.
349message ListRunsResponse {
350  // Runs are the runs of this page, highest id first, without jobs.
351  repeated Run runs = 1;
352  // NextPageToken is passed as page_token to get the next page. Empty when
353  // there is no next page.
354  string next_page_token = 2;
355}
356
357// GetRunRequest selects a run.
358message GetRunRequest {
359  // Repo is the repository name.
360  string repo = 1;
361  // RunId is the Run.id.
362  int64 run_id = 2;
363  // Attempt is the attempt to read. 0 means the latest.
364  int32 attempt = 3;
365}
366
367// GetRunResponse holds a run with its jobs.
368message GetRunResponse {
369  // Run is the run, as of the attempt asked.
370  Run run = 1;
371  // Jobs are the jobs of that attempt, with their steps, in the order of the
372  // workflow file (matrix instances in the order of the matrix). Jobs kept from
373  // an earlier attempt by a re-run of failed jobs are included, with their own
374  // RunJob.attempt. Empty for a run that failed on an invalid workflow file.
375  repeated RunJob jobs = 2;
376  // LatestAttempt is the latest attempt of the run, to offer the other ones.
377  int32 latest_attempt = 3;
378}
379
380// GetJobRequest selects a job.
381message GetJobRequest {
382  // Repo is the repository name.
383  string repo = 1;
384  // JobId is the RunJob.id.
385  string job_id = 2;
386  // Attempt is the RunJob.attempt to read. 0 means the latest.
387  int32 attempt = 3;
388}
389
390// GetJobResponse holds a job.
391message GetJobResponse {
392  // Job is the job with its steps.
393  RunJob job = 1;
394}
395
396// GetJobLogRequest selects the lines to stream.
397message GetJobLogRequest {
398  // Repo is the repository name.
399  string repo = 1;
400  // JobId is the RunJob.id.
401  string job_id = 2;
402  // Attempt is the RunJob.attempt whose log to read. 0 means the latest.
403  int32 attempt = 3;
404  // Offset is the number of the first line to send, counted from 0 across all
405  // steps (see Step.log_start). Negative is invalid_argument.
406  int64 offset = 4;
407  // Follow keeps the stream open while the job runs. See GetJobLog.
408  bool follow = 5;
409}
410
411// GetJobLogResponse is one message of the log stream.
412message GetJobLogResponse {
413  // Offset is the number of the first line of lines.
414  int64 offset = 1;
415  // Lines are consecutive lines of the log, at most 1,000, at most 64 KiB of
416  // text in total. Never empty.
417  repeated JobLogLine lines = 2;
418}
419
420// JobLogLine is one line of a job log, as the runner sent it.
421message JobLogLine {
422  // Step is the number of the step the line belongs to.
423  int32 step = 1;
424  // Time is when the runner produced the line, with nanosecond precision.
425  google.protobuf.Timestamp time = 2;
426  // Text is the line without its terminator, as in LogLine.text, including the
427  // "##[group]" and "##[endgroup]" markers. Clients show it escaped.
428  string text = 3;
429  // Continued is true when the line continues the line before it, which was
430  // too long for the runner to send whole (see LogLine.continued). Pieces keep
431  // their own line numbers, so offsets are the same as the runner's; a client
432  // that shows lines joins a continued line to the previous one. The raw log
433  // file already has them joined.
434  bool continued = 4;
435}
436
437// CancelRunRequest names the run to cancel.
438message CancelRunRequest {
439  // Repo is the repository name.
440  string repo = 1;
441  // RunId is the Run.id.
442  int64 run_id = 2;
443}
444
445// CancelRunResponse holds the run after the request.
446message CancelRunResponse {
447  // Run is the latest attempt of the run.
448  Run run = 1;
449}
450
451// RerunRunRequest names the run to run again.
452message RerunRunRequest {
453  // Repo is the repository name.
454  string repo = 1;
455  // RunId is the Run.id.
456  int64 run_id = 2;
457  // FailedOnly runs again only the jobs of the latest attempt that did not
458  // succeed (conclusion FAILURE, CANCELLED, TIMED_OUT or ACTION_REQUIRED) and
459  // the jobs that need them, directly or not, even if they were skipped. The
460  // other jobs keep their result, steps and log from the earlier attempt. When
461  // false, every job runs again.
462  bool failed_only = 3;
463}
464
465// RerunRunResponse holds the new attempt.
466message RerunRunResponse {
467  // Run is the run as of the new attempt, QUEUED.
468  Run run = 1;
469}
470
471// ListChecksRequest names the commit.
472message ListChecksRequest {
473  // Repo is the repository name.
474  string repo = 1;
475  // Sha is the full commit id (40 lowercase hexadecimal characters for SHA-1).
476  // Abbreviations and names are invalid_argument.
477  string sha = 2;
478}
479
480// ListChecksResponse holds the checks of a commit.
481message ListChecksResponse {
482  // Checks are the checks of the commit, one per job of the latest attempt of
483  // each run, ordered by creation time then name.
484  repeated Check checks = 1;
485  // Truncated is true when the commit has more checks than checks holds.
486  bool truncated = 2;
487}
488
489// ListRunnersRequest selects a page of runners.
490message ListRunnersRequest {
491  // PageSize is the maximum number of runners to return.
492  int32 page_size = 1;
493  // PageToken is the next_page_token of a previous response. Empty for the
494  // first page.
495  string page_token = 2;
496}
497
498// ListRunnersResponse is one page of runners.
499message ListRunnersResponse {
500  // Runners are the runners of this page, ordered by name.
501  repeated Runner runners = 1;
502  // NextPageToken is passed as page_token to get the next page. Empty when
503  // there is no next page.
504  string next_page_token = 2;
505}
506
507// RemoveRunnerRequest names the runner to remove.
508message RemoveRunnerRequest {
509  // RunnerId is the Runner.id.
510  string runner_id = 1;
511}
512
513// RemoveRunnerResponse is empty.
514message RemoveRunnerResponse {}

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