detached 49ac5fd

Merge pull request 'feat(ci): add actions, annotations and summaries to the CI protocol' (#9) from feat/ci2-protocol into main

commit
49ac5fd7a78a04c05aa33c86f7dcec5b6a4a58e7
author
bnema · · 2026-10-13 09:16 UTC
merge of
4db3b8b + b94fede · diff against the first parent
signature
SSH UnverifiedSHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivA The key is unknown
refs
tag: v0.2.0
10 files · +2129 -252
M README.md +2 -2
@@ -22,8 +22,8 @@ Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
2222 | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` |
2323 | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) |
2424 | `EventService` | `Watch` (streamed, resumable) |
25-| `RunnerService` | `RegisterRunner`, `FetchJob` (long poll), `UpdateJob`, `AppendLog` (offset-idempotent), `Heartbeat`, `WatchJob` (cancel requests, streamed), `CompleteJob` (idempotent); for CI runners |
26-| `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `CancelRun`, `RerunRun`, `ListChecks`, `ListRunners`, `RemoveRunner` |
25+| `RunnerService` | `RegisterRunner`, `FetchJob` (long poll), `UpdateJob` (steps, annotations), `AppendLog` (offset-idempotent), `Heartbeat`, `WatchJob` (cancel requests, streamed), `CompleteJob` (idempotent), `ResolveActions` (where to download the `uses:` actions), `UploadSummary` (job summary of a step); for CI runners |
26+| `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `ListAnnotations`, `GetStepSummaries`, `CancelRun`, `RerunRun`, `ListChecks`, `ListRunners`, `RemoveRunner` |
2727 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |
2828
2929 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
@@ -22,8 +22,8 @@ Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
22 | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` |22 | `MergeRequestService` | `CreateMergeRequest`, `ListMergeRequests`, `GetMergeRequest` (commits, diff, comments), `AddComment`, `ResolveComment`, `CloseMergeRequest`, `MergeMergeRequest`, `MarkRead` |
23 | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) |23 | `SessionService` | `CreateLoginLink`, `SignOutEverywhere` (owner only) |
24 | `EventService` | `Watch` (streamed, resumable) |24 | `EventService` | `Watch` (streamed, resumable) |
25-| `RunnerService` | `RegisterRunner`, `FetchJob` (long poll), `UpdateJob`, `AppendLog` (offset-idempotent), `Heartbeat`, `WatchJob` (cancel requests, streamed), `CompleteJob` (idempotent); for CI runners |25+| `RunnerService` | `RegisterRunner`, `FetchJob` (long poll), `UpdateJob` (steps, annotations), `AppendLog` (offset-idempotent), `Heartbeat`, `WatchJob` (cancel requests, streamed), `CompleteJob` (idempotent), `ResolveActions` (where to download the `uses:` actions), `UploadSummary` (job summary of a step); for CI runners |
26-| `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `CancelRun`, `RerunRun`, `ListChecks`, `ListRunners`, `RemoveRunner` |26+| `RunService` | `ListRuns`, `GetRun`, `GetJob`, `GetJobLog` (streamed, follow), `ListAnnotations`, `GetStepSummaries`, `CancelRun`, `RerunRun`, `ListChecks`, `ListRunners`, `RemoveRunner` |
27 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |27 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |
28 28
29 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.29 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
M gen/ermite/ermiteconnect/run.connect.go +101 -9
@@ -41,6 +41,12 @@ const (
4141 RunServiceGetRunProcedure = "/ermite.RunService/GetRun"
4242 // RunServiceGetJobProcedure is the fully-qualified name of the RunService's GetJob RPC.
4343 RunServiceGetJobProcedure = "/ermite.RunService/GetJob"
44+ // RunServiceListAnnotationsProcedure is the fully-qualified name of the RunService's
45+ // ListAnnotations RPC.
46+ RunServiceListAnnotationsProcedure = "/ermite.RunService/ListAnnotations"
47+ // RunServiceGetStepSummariesProcedure is the fully-qualified name of the RunService's
48+ // GetStepSummaries RPC.
49+ RunServiceGetStepSummariesProcedure = "/ermite.RunService/GetStepSummaries"
4450 // RunServiceGetJobLogProcedure is the fully-qualified name of the RunService's GetJobLog RPC.
4551 RunServiceGetJobLogProcedure = "/ermite.RunService/GetJobLog"
4652 // RunServiceCancelRunProcedure is the fully-qualified name of the RunService's CancelRun RPC.
@@ -70,6 +76,25 @@ type RunServiceClient interface {
7076 // GetJob returns one job with its steps. Fails with not_found if the job
7177 // or the attempt does not exist.
7278 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
79+ // ListAnnotations lists the annotations of a run attempt, optionally of one
80+ // job, ordered by job (as in GetRun), step number, then the order in which
81+ // the step produced them. For each job it gives the annotations of the
82+ // attempt in which that job executed (RunJob.attempt), which is lower than
83+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
84+ // 1,000 annotations (truncated tells). A run without annotations gives an
85+ // empty list. Only servers with the feature "ci.annotations" implement it
86+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
87+ // the job does not exist, or if the job is not a job of the run.
88+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
89+ // GetStepSummaries returns the job summaries (the Markdown written to
90+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
91+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
92+ // steps that have one, in step order; truncated says there are more. Needs
93+ // the same access as GetJob. Only servers with the feature
94+ // "ci.summaries" implement it (unimplemented otherwise). A job without
95+ // summaries gives an empty list. Fails with not_found if the job or the
96+ // attempt does not exist.
97+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
7398 // GetJobLog streams the lines of the log of a job, from a line number. The
7499 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
75100 // text each.
@@ -148,6 +173,18 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
148173 connect.WithSchema(runServiceMethods.ByName("GetJob")),
149174 connect.WithClientOptions(opts...),
150175 ),
176+ listAnnotations: connect.NewClient[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse](
177+ httpClient,
178+ baseURL+RunServiceListAnnotationsProcedure,
179+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
180+ connect.WithClientOptions(opts...),
181+ ),
182+ getStepSummaries: connect.NewClient[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse](
183+ httpClient,
184+ baseURL+RunServiceGetStepSummariesProcedure,
185+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
186+ connect.WithClientOptions(opts...),
187+ ),
151188 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](
152189 httpClient,
153190 baseURL+RunServiceGetJobLogProcedure,
@@ -189,15 +226,17 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
189226
190227 // runServiceClient implements RunServiceClient.
191228 type runServiceClient struct {
192- listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]
193- getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]
194- getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]
195- getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]
196- cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]
197- rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]
198- listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]
199- listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]
200- removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]
229+ listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]
230+ getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]
231+ getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]
232+ listAnnotations *connect.Client[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse]
233+ getStepSummaries *connect.Client[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse]
234+ getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]
235+ cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]
236+ rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]
237+ listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]
238+ listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]
239+ removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]
201240 }
202241
203242 // ListRuns calls ermite.RunService.ListRuns.
@@ -215,6 +254,16 @@ func (c *runServiceClient) GetJob(ctx context.Context, req *connect.Request[ermi
215254 return c.getJob.CallUnary(ctx, req)
216255 }
217256
257+// ListAnnotations calls ermite.RunService.ListAnnotations.
258+func (c *runServiceClient) ListAnnotations(ctx context.Context, req *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
259+ return c.listAnnotations.CallUnary(ctx, req)
260+}
261+
262+// GetStepSummaries calls ermite.RunService.GetStepSummaries.
263+func (c *runServiceClient) GetStepSummaries(ctx context.Context, req *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
264+ return c.getStepSummaries.CallUnary(ctx, req)
265+}
266+
218267 // GetJobLog calls ermite.RunService.GetJobLog.
219268 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {
220269 return c.getJobLog.CallServerStream(ctx, req)
@@ -260,6 +309,25 @@ type RunServiceHandler interface {
260309 // GetJob returns one job with its steps. Fails with not_found if the job
261310 // or the attempt does not exist.
262311 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
312+ // ListAnnotations lists the annotations of a run attempt, optionally of one
313+ // job, ordered by job (as in GetRun), step number, then the order in which
314+ // the step produced them. For each job it gives the annotations of the
315+ // attempt in which that job executed (RunJob.attempt), which is lower than
316+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
317+ // 1,000 annotations (truncated tells). A run without annotations gives an
318+ // empty list. Only servers with the feature "ci.annotations" implement it
319+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
320+ // the job does not exist, or if the job is not a job of the run.
321+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
322+ // GetStepSummaries returns the job summaries (the Markdown written to
323+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
324+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
325+ // steps that have one, in step order; truncated says there are more. Needs
326+ // the same access as GetJob. Only servers with the feature
327+ // "ci.summaries" implement it (unimplemented otherwise). A job without
328+ // summaries gives an empty list. Fails with not_found if the job or the
329+ // attempt does not exist.
330+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
263331 // GetJobLog streams the lines of the log of a job, from a line number. The
264332 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
265333 // text each.
@@ -334,6 +402,18 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
334402 connect.WithSchema(runServiceMethods.ByName("GetJob")),
335403 connect.WithHandlerOptions(opts...),
336404 )
405+ runServiceListAnnotationsHandler := connect.NewUnaryHandler(
406+ RunServiceListAnnotationsProcedure,
407+ svc.ListAnnotations,
408+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
409+ connect.WithHandlerOptions(opts...),
410+ )
411+ runServiceGetStepSummariesHandler := connect.NewUnaryHandler(
412+ RunServiceGetStepSummariesProcedure,
413+ svc.GetStepSummaries,
414+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
415+ connect.WithHandlerOptions(opts...),
416+ )
337417 runServiceGetJobLogHandler := connect.NewServerStreamHandler(
338418 RunServiceGetJobLogProcedure,
339419 svc.GetJobLog,
@@ -378,6 +458,10 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
378458 runServiceGetRunHandler.ServeHTTP(w, r)
379459 case RunServiceGetJobProcedure:
380460 runServiceGetJobHandler.ServeHTTP(w, r)
461+ case RunServiceListAnnotationsProcedure:
462+ runServiceListAnnotationsHandler.ServeHTTP(w, r)
463+ case RunServiceGetStepSummariesProcedure:
464+ runServiceGetStepSummariesHandler.ServeHTTP(w, r)
381465 case RunServiceGetJobLogProcedure:
382466 runServiceGetJobLogHandler.ServeHTTP(w, r)
383467 case RunServiceCancelRunProcedure:
@@ -411,6 +495,14 @@ func (UnimplementedRunServiceHandler) GetJob(context.Context, *connect.Request[e
411495 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))
412496 }
413497
498+func (UnimplementedRunServiceHandler) ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
499+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.ListAnnotations is not implemented"))
500+}
501+
502+func (UnimplementedRunServiceHandler) GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
503+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetStepSummaries is not implemented"))
504+}
505+
414506 func (UnimplementedRunServiceHandler) GetJobLog(context.Context, *connect.Request[ermite.GetJobLogRequest], *connect.ServerStream[ermite.GetJobLogResponse]) error {
415507 return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJobLog is not implemented"))
416508 }
@@ -41,6 +41,12 @@ const (
41 RunServiceGetRunProcedure = "/ermite.RunService/GetRun"41 RunServiceGetRunProcedure = "/ermite.RunService/GetRun"
42 // RunServiceGetJobProcedure is the fully-qualified name of the RunService's GetJob RPC.42 // RunServiceGetJobProcedure is the fully-qualified name of the RunService's GetJob RPC.
43 RunServiceGetJobProcedure = "/ermite.RunService/GetJob"43 RunServiceGetJobProcedure = "/ermite.RunService/GetJob"
44+ // RunServiceListAnnotationsProcedure is the fully-qualified name of the RunService's
45+ // ListAnnotations RPC.
46+ RunServiceListAnnotationsProcedure = "/ermite.RunService/ListAnnotations"
47+ // RunServiceGetStepSummariesProcedure is the fully-qualified name of the RunService's
48+ // GetStepSummaries RPC.
49+ RunServiceGetStepSummariesProcedure = "/ermite.RunService/GetStepSummaries"
44 // RunServiceGetJobLogProcedure is the fully-qualified name of the RunService's GetJobLog RPC.50 // RunServiceGetJobLogProcedure is the fully-qualified name of the RunService's GetJobLog RPC.
45 RunServiceGetJobLogProcedure = "/ermite.RunService/GetJobLog"51 RunServiceGetJobLogProcedure = "/ermite.RunService/GetJobLog"
46 // RunServiceCancelRunProcedure is the fully-qualified name of the RunService's CancelRun RPC.52 // RunServiceCancelRunProcedure is the fully-qualified name of the RunService's CancelRun RPC.
@@ -70,6 +76,25 @@ type RunServiceClient interface {
70 // GetJob returns one job with its steps. Fails with not_found if the job76 // GetJob returns one job with its steps. Fails with not_found if the job
71 // or the attempt does not exist.77 // or the attempt does not exist.
72 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)78 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
79+ // ListAnnotations lists the annotations of a run attempt, optionally of one
80+ // job, ordered by job (as in GetRun), step number, then the order in which
81+ // the step produced them. For each job it gives the annotations of the
82+ // attempt in which that job executed (RunJob.attempt), which is lower than
83+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
84+ // 1,000 annotations (truncated tells). A run without annotations gives an
85+ // empty list. Only servers with the feature "ci.annotations" implement it
86+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
87+ // the job does not exist, or if the job is not a job of the run.
88+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
89+ // GetStepSummaries returns the job summaries (the Markdown written to
90+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
91+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
92+ // steps that have one, in step order; truncated says there are more. Needs
93+ // the same access as GetJob. Only servers with the feature
94+ // "ci.summaries" implement it (unimplemented otherwise). A job without
95+ // summaries gives an empty list. Fails with not_found if the job or the
96+ // attempt does not exist.
97+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
73 // GetJobLog streams the lines of the log of a job, from a line number. The98 // GetJobLog streams the lines of the log of a job, from a line number. The
74 // server sends them in order in messages of at most 1,000 lines and 64 KiB of99 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
75 // text each.100 // text each.
@@ -148,6 +173,18 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
148 connect.WithSchema(runServiceMethods.ByName("GetJob")),173 connect.WithSchema(runServiceMethods.ByName("GetJob")),
149 connect.WithClientOptions(opts...),174 connect.WithClientOptions(opts...),
150 ),175 ),
176+ listAnnotations: connect.NewClient[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse](
177+ httpClient,
178+ baseURL+RunServiceListAnnotationsProcedure,
179+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
180+ connect.WithClientOptions(opts...),
181+ ),
182+ getStepSummaries: connect.NewClient[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse](
183+ httpClient,
184+ baseURL+RunServiceGetStepSummariesProcedure,
185+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
186+ connect.WithClientOptions(opts...),
187+ ),
151 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](188 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](
152 httpClient,189 httpClient,
153 baseURL+RunServiceGetJobLogProcedure,190 baseURL+RunServiceGetJobLogProcedure,
@@ -189,15 +226,17 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
189 226
190 // runServiceClient implements RunServiceClient.227 // runServiceClient implements RunServiceClient.
191 type runServiceClient struct {228 type runServiceClient struct {
192- listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]229+ listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]
193- getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]230+ getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]
194- getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]231+ getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]
195- getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]232+ listAnnotations *connect.Client[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse]
196- cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]233+ getStepSummaries *connect.Client[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse]
197- rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]234+ getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]
198- listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]235+ cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]
199- listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]236+ rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]
200- removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]237+ listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]
238+ listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]
239+ removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]
201 }240 }
202 241
203 // ListRuns calls ermite.RunService.ListRuns.242 // ListRuns calls ermite.RunService.ListRuns.
@@ -215,6 +254,16 @@ func (c *runServiceClient) GetJob(ctx context.Context, req *connect.Request[ermi
215 return c.getJob.CallUnary(ctx, req)254 return c.getJob.CallUnary(ctx, req)
216 }255 }
217 256
257+// ListAnnotations calls ermite.RunService.ListAnnotations.
258+func (c *runServiceClient) ListAnnotations(ctx context.Context, req *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
259+ return c.listAnnotations.CallUnary(ctx, req)
260+}
261+
262+// GetStepSummaries calls ermite.RunService.GetStepSummaries.
263+func (c *runServiceClient) GetStepSummaries(ctx context.Context, req *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
264+ return c.getStepSummaries.CallUnary(ctx, req)
265+}
266+
218 // GetJobLog calls ermite.RunService.GetJobLog.267 // GetJobLog calls ermite.RunService.GetJobLog.
219 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {268 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {
220 return c.getJobLog.CallServerStream(ctx, req)269 return c.getJobLog.CallServerStream(ctx, req)
@@ -260,6 +309,25 @@ type RunServiceHandler interface {
260 // GetJob returns one job with its steps. Fails with not_found if the job309 // GetJob returns one job with its steps. Fails with not_found if the job
261 // or the attempt does not exist.310 // or the attempt does not exist.
262 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)311 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
312+ // ListAnnotations lists the annotations of a run attempt, optionally of one
313+ // job, ordered by job (as in GetRun), step number, then the order in which
314+ // the step produced them. For each job it gives the annotations of the
315+ // attempt in which that job executed (RunJob.attempt), which is lower than
316+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
317+ // 1,000 annotations (truncated tells). A run without annotations gives an
318+ // empty list. Only servers with the feature "ci.annotations" implement it
319+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
320+ // the job does not exist, or if the job is not a job of the run.
321+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
322+ // GetStepSummaries returns the job summaries (the Markdown written to
323+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
324+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
325+ // steps that have one, in step order; truncated says there are more. Needs
326+ // the same access as GetJob. Only servers with the feature
327+ // "ci.summaries" implement it (unimplemented otherwise). A job without
328+ // summaries gives an empty list. Fails with not_found if the job or the
329+ // attempt does not exist.
330+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
263 // GetJobLog streams the lines of the log of a job, from a line number. The331 // GetJobLog streams the lines of the log of a job, from a line number. The
264 // server sends them in order in messages of at most 1,000 lines and 64 KiB of332 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
265 // text each.333 // text each.
@@ -334,6 +402,18 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
334 connect.WithSchema(runServiceMethods.ByName("GetJob")),402 connect.WithSchema(runServiceMethods.ByName("GetJob")),
335 connect.WithHandlerOptions(opts...),403 connect.WithHandlerOptions(opts...),
336 )404 )
405+ runServiceListAnnotationsHandler := connect.NewUnaryHandler(
406+ RunServiceListAnnotationsProcedure,
407+ svc.ListAnnotations,
408+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
409+ connect.WithHandlerOptions(opts...),
410+ )
411+ runServiceGetStepSummariesHandler := connect.NewUnaryHandler(
412+ RunServiceGetStepSummariesProcedure,
413+ svc.GetStepSummaries,
414+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
415+ connect.WithHandlerOptions(opts...),
416+ )
337 runServiceGetJobLogHandler := connect.NewServerStreamHandler(417 runServiceGetJobLogHandler := connect.NewServerStreamHandler(
338 RunServiceGetJobLogProcedure,418 RunServiceGetJobLogProcedure,
339 svc.GetJobLog,419 svc.GetJobLog,
@@ -378,6 +458,10 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
378 runServiceGetRunHandler.ServeHTTP(w, r)458 runServiceGetRunHandler.ServeHTTP(w, r)
379 case RunServiceGetJobProcedure:459 case RunServiceGetJobProcedure:
380 runServiceGetJobHandler.ServeHTTP(w, r)460 runServiceGetJobHandler.ServeHTTP(w, r)
461+ case RunServiceListAnnotationsProcedure:
462+ runServiceListAnnotationsHandler.ServeHTTP(w, r)
463+ case RunServiceGetStepSummariesProcedure:
464+ runServiceGetStepSummariesHandler.ServeHTTP(w, r)
381 case RunServiceGetJobLogProcedure:465 case RunServiceGetJobLogProcedure:
382 runServiceGetJobLogHandler.ServeHTTP(w, r)466 runServiceGetJobLogHandler.ServeHTTP(w, r)
383 case RunServiceCancelRunProcedure:467 case RunServiceCancelRunProcedure:
@@ -411,6 +495,14 @@ func (UnimplementedRunServiceHandler) GetJob(context.Context, *connect.Request[e
411 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))495 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))
412 }496 }
413 497
498+func (UnimplementedRunServiceHandler) ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
499+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.ListAnnotations is not implemented"))
500+}
501+
502+func (UnimplementedRunServiceHandler) GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
503+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetStepSummaries is not implemented"))
504+}
505+
414 func (UnimplementedRunServiceHandler) GetJobLog(context.Context, *connect.Request[ermite.GetJobLogRequest], *connect.ServerStream[ermite.GetJobLogResponse]) error {506 func (UnimplementedRunServiceHandler) GetJobLog(context.Context, *connect.Request[ermite.GetJobLogRequest], *connect.ServerStream[ermite.GetJobLogResponse]) error {
415 return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJobLog is not implemented"))507 return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJobLog is not implemented"))
416 }508 }
M gen/ermite/ermiteconnect/runner.connect.go +184 -12
@@ -51,6 +51,12 @@ const (
5151 // RunnerServiceCompleteJobProcedure is the fully-qualified name of the RunnerService's CompleteJob
5252 // RPC.
5353 RunnerServiceCompleteJobProcedure = "/ermite.RunnerService/CompleteJob"
54+ // RunnerServiceResolveActionsProcedure is the fully-qualified name of the RunnerService's
55+ // ResolveActions RPC.
56+ RunnerServiceResolveActionsProcedure = "/ermite.RunnerService/ResolveActions"
57+ // RunnerServiceUploadSummaryProcedure is the fully-qualified name of the RunnerService's
58+ // UploadSummary RPC.
59+ RunnerServiceUploadSummaryProcedure = "/ermite.RunnerService/UploadSummary"
5460 )
5561
5662 // RunnerServiceClient is a client for the ermite.RunnerService service.
@@ -105,10 +111,21 @@ type RunnerServiceClient interface {
105111 // identical call changes nothing, so a runner may retry after a network
106112 // error. To end the job use CompleteJob.
107113 //
108- // Fails with invalid_argument if a rule is broken, with failed_precondition
109- // if a step goes back (a COMPLETED step cannot change, a step cannot go from
110- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail
111- // if the job has ended.
114+ // Annotations are applied with the steps, in the same atomic step: for each
115+ // step_number present in annotations, the annotations of that step stored
116+ // so far are replaced by the ones of the request, so a retry never
117+ // duplicates them. A step number absent from the request keeps its
118+ // annotations. The step of an annotation need not be in the steps of the
119+ // same call, and may already be COMPLETED: its annotations can still be
120+ // replaced (the rule that a COMPLETED step cannot change applies to
121+ // StepUpdate, not to annotations), until the job ends. A runner sends one
122+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
123+ // so replacements apply in the order of the calls.
124+ //
125+ // Fails with invalid_argument if a rule is broken (including the annotation
126+ // limits), with failed_precondition if a step goes back (a COMPLETED step
127+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
128+ // failed_precondition and a JobEnded detail if the job has ended.
112129 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
113130 // AppendLog appends lines to the log of a job. Needs the job token.
114131 //
@@ -213,9 +230,57 @@ type RunnerServiceClient interface {
213230 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
214231 // they never started and the job did not end by cancellation).
215232 //
216- // Fails with invalid_argument if a rule is broken (including the output
217- // limits) and failed_precondition if a step goes back, as in UpdateJob.
233+ // Annotations are applied as in UpdateJob (replacement per step number, also
234+ // for COMPLETED steps and steps not in steps), together with the conclusion.
235+ // Summaries are not part of this call: a runner sends them with
236+ // UploadSummary before it.
237+ //
238+ // Fails with invalid_argument if a rule is broken (including the output and
239+ // annotation limits) and failed_precondition if a step goes back, as in
240+ // UpdateJob.
218241 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
242+ // ResolveActions turns the "uses" of workflow and action steps into what the
243+ // runner needs to download the actions, as GitHub's action download info
244+ // does. Needs the job token; the job_id must be the one of the token. It
245+ // may be called as often as needed while the job runs (the runner calls it
246+ // once per level of composite actions, see the runner's depth limit of 9).
247+ // The runner then downloads each archive itself, from the sandbox, with the
248+ // token of the ResolvedAction when there is one.
249+ //
250+ // The response has one ResolvedAction per ActionRef, in the same order. A
251+ // reference that cannot be resolved (unknown repository, tag or branch, a
252+ // repository without access, a "uses" that GitHub itself would reject) does
253+ // not fail the call: its ResolvedAction has only ref and error, where error
254+ // is the message GitHub gives for the same failure, which the runner prints
255+ // as is. Only a failure of the call itself (credential, ended job, bad
256+ // request, server error) is an RPC error; the runner then fails the job.
257+ //
258+ // Resolution is stable for a run attempt: the same ref resolves to the same
259+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
260+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
261+ // job gets its own (ResolvedAction.token).
262+ //
263+ // Fails with unauthenticated or permission_denied as the other job RPCs,
264+ // with failed_precondition and a JobEnded detail if the job has ended, and
265+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
266+ // local action ("./path") or a Docker image ("docker://"), which the runner
267+ // handles without the server.
268+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
269+ // UploadSummary stores the job summary of one step: the Markdown that the
270+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
271+ // The runner masks it before sending it, and sends it after the step ended
272+ // and before CompleteJob.
273+ //
274+ // It is idempotent: the summary of a step is replaced by each call, so a
275+ // retry changes nothing, and an empty markdown removes the summary of the
276+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
277+ // server reads requests of up to 1 MiB plus the envelope (job id, step
278+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
279+ // their own message size limit above that.
280+ //
281+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
282+ // and with failed_precondition and a JobEnded detail if the job has ended.
283+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
219284 }
220285
221286 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it
@@ -271,6 +336,18 @@ func NewRunnerServiceClient(httpClient connect.HTTPClient, baseURL string, opts
271336 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
272337 connect.WithClientOptions(opts...),
273338 ),
339+ resolveActions: connect.NewClient[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse](
340+ httpClient,
341+ baseURL+RunnerServiceResolveActionsProcedure,
342+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
343+ connect.WithClientOptions(opts...),
344+ ),
345+ uploadSummary: connect.NewClient[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse](
346+ httpClient,
347+ baseURL+RunnerServiceUploadSummaryProcedure,
348+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
349+ connect.WithClientOptions(opts...),
350+ ),
274351 }
275352 }
276353
@@ -283,6 +360,8 @@ type runnerServiceClient struct {
283360 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]
284361 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]
285362 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]
363+ resolveActions *connect.Client[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse]
364+ uploadSummary *connect.Client[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse]
286365 }
287366
288367 // RegisterRunner calls ermite.RunnerService.RegisterRunner.
@@ -320,6 +399,16 @@ func (c *runnerServiceClient) CompleteJob(ctx context.Context, req *connect.Requ
320399 return c.completeJob.CallUnary(ctx, req)
321400 }
322401
402+// ResolveActions calls ermite.RunnerService.ResolveActions.
403+func (c *runnerServiceClient) ResolveActions(ctx context.Context, req *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
404+ return c.resolveActions.CallUnary(ctx, req)
405+}
406+
407+// UploadSummary calls ermite.RunnerService.UploadSummary.
408+func (c *runnerServiceClient) UploadSummary(ctx context.Context, req *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
409+ return c.uploadSummary.CallUnary(ctx, req)
410+}
411+
323412 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.
324413 type RunnerServiceHandler interface {
325414 // RegisterRunner registers a runner and returns its runner token, which is
@@ -372,10 +461,21 @@ type RunnerServiceHandler interface {
372461 // identical call changes nothing, so a runner may retry after a network
373462 // error. To end the job use CompleteJob.
374463 //
375- // Fails with invalid_argument if a rule is broken, with failed_precondition
376- // if a step goes back (a COMPLETED step cannot change, a step cannot go from
377- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail
378- // if the job has ended.
464+ // Annotations are applied with the steps, in the same atomic step: for each
465+ // step_number present in annotations, the annotations of that step stored
466+ // so far are replaced by the ones of the request, so a retry never
467+ // duplicates them. A step number absent from the request keeps its
468+ // annotations. The step of an annotation need not be in the steps of the
469+ // same call, and may already be COMPLETED: its annotations can still be
470+ // replaced (the rule that a COMPLETED step cannot change applies to
471+ // StepUpdate, not to annotations), until the job ends. A runner sends one
472+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
473+ // so replacements apply in the order of the calls.
474+ //
475+ // Fails with invalid_argument if a rule is broken (including the annotation
476+ // limits), with failed_precondition if a step goes back (a COMPLETED step
477+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
478+ // failed_precondition and a JobEnded detail if the job has ended.
379479 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
380480 // AppendLog appends lines to the log of a job. Needs the job token.
381481 //
@@ -480,9 +580,57 @@ type RunnerServiceHandler interface {
480580 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
481581 // they never started and the job did not end by cancellation).
482582 //
483- // Fails with invalid_argument if a rule is broken (including the output
484- // limits) and failed_precondition if a step goes back, as in UpdateJob.
583+ // Annotations are applied as in UpdateJob (replacement per step number, also
584+ // for COMPLETED steps and steps not in steps), together with the conclusion.
585+ // Summaries are not part of this call: a runner sends them with
586+ // UploadSummary before it.
587+ //
588+ // Fails with invalid_argument if a rule is broken (including the output and
589+ // annotation limits) and failed_precondition if a step goes back, as in
590+ // UpdateJob.
485591 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
592+ // ResolveActions turns the "uses" of workflow and action steps into what the
593+ // runner needs to download the actions, as GitHub's action download info
594+ // does. Needs the job token; the job_id must be the one of the token. It
595+ // may be called as often as needed while the job runs (the runner calls it
596+ // once per level of composite actions, see the runner's depth limit of 9).
597+ // The runner then downloads each archive itself, from the sandbox, with the
598+ // token of the ResolvedAction when there is one.
599+ //
600+ // The response has one ResolvedAction per ActionRef, in the same order. A
601+ // reference that cannot be resolved (unknown repository, tag or branch, a
602+ // repository without access, a "uses" that GitHub itself would reject) does
603+ // not fail the call: its ResolvedAction has only ref and error, where error
604+ // is the message GitHub gives for the same failure, which the runner prints
605+ // as is. Only a failure of the call itself (credential, ended job, bad
606+ // request, server error) is an RPC error; the runner then fails the job.
607+ //
608+ // Resolution is stable for a run attempt: the same ref resolves to the same
609+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
610+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
611+ // job gets its own (ResolvedAction.token).
612+ //
613+ // Fails with unauthenticated or permission_denied as the other job RPCs,
614+ // with failed_precondition and a JobEnded detail if the job has ended, and
615+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
616+ // local action ("./path") or a Docker image ("docker://"), which the runner
617+ // handles without the server.
618+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
619+ // UploadSummary stores the job summary of one step: the Markdown that the
620+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
621+ // The runner masks it before sending it, and sends it after the step ended
622+ // and before CompleteJob.
623+ //
624+ // It is idempotent: the summary of a step is replaced by each call, so a
625+ // retry changes nothing, and an empty markdown removes the summary of the
626+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
627+ // server reads requests of up to 1 MiB plus the envelope (job id, step
628+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
629+ // their own message size limit above that.
630+ //
631+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
632+ // and with failed_precondition and a JobEnded detail if the job has ended.
633+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
486634 }
487635
488636 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the
@@ -534,6 +682,18 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
534682 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
535683 connect.WithHandlerOptions(opts...),
536684 )
685+ runnerServiceResolveActionsHandler := connect.NewUnaryHandler(
686+ RunnerServiceResolveActionsProcedure,
687+ svc.ResolveActions,
688+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
689+ connect.WithHandlerOptions(opts...),
690+ )
691+ runnerServiceUploadSummaryHandler := connect.NewUnaryHandler(
692+ RunnerServiceUploadSummaryProcedure,
693+ svc.UploadSummary,
694+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
695+ connect.WithHandlerOptions(opts...),
696+ )
537697 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
538698 switch r.URL.Path {
539699 case RunnerServiceRegisterRunnerProcedure:
@@ -550,6 +710,10 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
550710 runnerServiceWatchJobHandler.ServeHTTP(w, r)
551711 case RunnerServiceCompleteJobProcedure:
552712 runnerServiceCompleteJobHandler.ServeHTTP(w, r)
713+ case RunnerServiceResolveActionsProcedure:
714+ runnerServiceResolveActionsHandler.ServeHTTP(w, r)
715+ case RunnerServiceUploadSummaryProcedure:
716+ runnerServiceUploadSummaryHandler.ServeHTTP(w, r)
553717 default:
554718 http.NotFound(w, r)
555719 }
@@ -586,3 +750,11 @@ func (UnimplementedRunnerServiceHandler) WatchJob(context.Context, *connect.Requ
586750 func (UnimplementedRunnerServiceHandler) CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error) {
587751 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.CompleteJob is not implemented"))
588752 }
753+
754+func (UnimplementedRunnerServiceHandler) ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
755+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.ResolveActions is not implemented"))
756+}
757+
758+func (UnimplementedRunnerServiceHandler) UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
759+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.UploadSummary is not implemented"))
760+}
@@ -51,6 +51,12 @@ const (
51 // RunnerServiceCompleteJobProcedure is the fully-qualified name of the RunnerService's CompleteJob51 // RunnerServiceCompleteJobProcedure is the fully-qualified name of the RunnerService's CompleteJob
52 // RPC.52 // RPC.
53 RunnerServiceCompleteJobProcedure = "/ermite.RunnerService/CompleteJob"53 RunnerServiceCompleteJobProcedure = "/ermite.RunnerService/CompleteJob"
54+ // RunnerServiceResolveActionsProcedure is the fully-qualified name of the RunnerService's
55+ // ResolveActions RPC.
56+ RunnerServiceResolveActionsProcedure = "/ermite.RunnerService/ResolveActions"
57+ // RunnerServiceUploadSummaryProcedure is the fully-qualified name of the RunnerService's
58+ // UploadSummary RPC.
59+ RunnerServiceUploadSummaryProcedure = "/ermite.RunnerService/UploadSummary"
54 )60 )
55 61
56 // RunnerServiceClient is a client for the ermite.RunnerService service.62 // RunnerServiceClient is a client for the ermite.RunnerService service.
@@ -105,10 +111,21 @@ type RunnerServiceClient interface {
105 // identical call changes nothing, so a runner may retry after a network111 // identical call changes nothing, so a runner may retry after a network
106 // error. To end the job use CompleteJob.112 // error. To end the job use CompleteJob.
107 //113 //
108- // Fails with invalid_argument if a rule is broken, with failed_precondition114+ // Annotations are applied with the steps, in the same atomic step: for each
109- // if a step goes back (a COMPLETED step cannot change, a step cannot go from115+ // step_number present in annotations, the annotations of that step stored
110- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail116+ // so far are replaced by the ones of the request, so a retry never
111- // if the job has ended.117+ // duplicates them. A step number absent from the request keeps its
118+ // annotations. The step of an annotation need not be in the steps of the
119+ // same call, and may already be COMPLETED: its annotations can still be
120+ // replaced (the rule that a COMPLETED step cannot change applies to
121+ // StepUpdate, not to annotations), until the job ends. A runner sends one
122+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
123+ // so replacements apply in the order of the calls.
124+ //
125+ // Fails with invalid_argument if a rule is broken (including the annotation
126+ // limits), with failed_precondition if a step goes back (a COMPLETED step
127+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
128+ // failed_precondition and a JobEnded detail if the job has ended.
112 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)129 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
113 // AppendLog appends lines to the log of a job. Needs the job token.130 // AppendLog appends lines to the log of a job. Needs the job token.
114 //131 //
@@ -213,9 +230,57 @@ type RunnerServiceClient interface {
213 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when230 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
214 // they never started and the job did not end by cancellation).231 // they never started and the job did not end by cancellation).
215 //232 //
216- // Fails with invalid_argument if a rule is broken (including the output233+ // Annotations are applied as in UpdateJob (replacement per step number, also
217- // limits) and failed_precondition if a step goes back, as in UpdateJob.234+ // for COMPLETED steps and steps not in steps), together with the conclusion.
235+ // Summaries are not part of this call: a runner sends them with
236+ // UploadSummary before it.
237+ //
238+ // Fails with invalid_argument if a rule is broken (including the output and
239+ // annotation limits) and failed_precondition if a step goes back, as in
240+ // UpdateJob.
218 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)241 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
242+ // ResolveActions turns the "uses" of workflow and action steps into what the
243+ // runner needs to download the actions, as GitHub's action download info
244+ // does. Needs the job token; the job_id must be the one of the token. It
245+ // may be called as often as needed while the job runs (the runner calls it
246+ // once per level of composite actions, see the runner's depth limit of 9).
247+ // The runner then downloads each archive itself, from the sandbox, with the
248+ // token of the ResolvedAction when there is one.
249+ //
250+ // The response has one ResolvedAction per ActionRef, in the same order. A
251+ // reference that cannot be resolved (unknown repository, tag or branch, a
252+ // repository without access, a "uses" that GitHub itself would reject) does
253+ // not fail the call: its ResolvedAction has only ref and error, where error
254+ // is the message GitHub gives for the same failure, which the runner prints
255+ // as is. Only a failure of the call itself (credential, ended job, bad
256+ // request, server error) is an RPC error; the runner then fails the job.
257+ //
258+ // Resolution is stable for a run attempt: the same ref resolves to the same
259+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
260+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
261+ // job gets its own (ResolvedAction.token).
262+ //
263+ // Fails with unauthenticated or permission_denied as the other job RPCs,
264+ // with failed_precondition and a JobEnded detail if the job has ended, and
265+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
266+ // local action ("./path") or a Docker image ("docker://"), which the runner
267+ // handles without the server.
268+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
269+ // UploadSummary stores the job summary of one step: the Markdown that the
270+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
271+ // The runner masks it before sending it, and sends it after the step ended
272+ // and before CompleteJob.
273+ //
274+ // It is idempotent: the summary of a step is replaced by each call, so a
275+ // retry changes nothing, and an empty markdown removes the summary of the
276+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
277+ // server reads requests of up to 1 MiB plus the envelope (job id, step
278+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
279+ // their own message size limit above that.
280+ //
281+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
282+ // and with failed_precondition and a JobEnded detail if the job has ended.
283+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
219 }284 }
220 285
221 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it286 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it
@@ -271,6 +336,18 @@ func NewRunnerServiceClient(httpClient connect.HTTPClient, baseURL string, opts
271 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),336 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
272 connect.WithClientOptions(opts...),337 connect.WithClientOptions(opts...),
273 ),338 ),
339+ resolveActions: connect.NewClient[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse](
340+ httpClient,
341+ baseURL+RunnerServiceResolveActionsProcedure,
342+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
343+ connect.WithClientOptions(opts...),
344+ ),
345+ uploadSummary: connect.NewClient[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse](
346+ httpClient,
347+ baseURL+RunnerServiceUploadSummaryProcedure,
348+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
349+ connect.WithClientOptions(opts...),
350+ ),
274 }351 }
275 }352 }
276 353
@@ -283,6 +360,8 @@ type runnerServiceClient struct {
283 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]360 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]
284 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]361 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]
285 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]362 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]
363+ resolveActions *connect.Client[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse]
364+ uploadSummary *connect.Client[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse]
286 }365 }
287 366
288 // RegisterRunner calls ermite.RunnerService.RegisterRunner.367 // RegisterRunner calls ermite.RunnerService.RegisterRunner.
@@ -320,6 +399,16 @@ func (c *runnerServiceClient) CompleteJob(ctx context.Context, req *connect.Requ
320 return c.completeJob.CallUnary(ctx, req)399 return c.completeJob.CallUnary(ctx, req)
321 }400 }
322 401
402+// ResolveActions calls ermite.RunnerService.ResolveActions.
403+func (c *runnerServiceClient) ResolveActions(ctx context.Context, req *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
404+ return c.resolveActions.CallUnary(ctx, req)
405+}
406+
407+// UploadSummary calls ermite.RunnerService.UploadSummary.
408+func (c *runnerServiceClient) UploadSummary(ctx context.Context, req *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
409+ return c.uploadSummary.CallUnary(ctx, req)
410+}
411+
323 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.412 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.
324 type RunnerServiceHandler interface {413 type RunnerServiceHandler interface {
325 // RegisterRunner registers a runner and returns its runner token, which is414 // RegisterRunner registers a runner and returns its runner token, which is
@@ -372,10 +461,21 @@ type RunnerServiceHandler interface {
372 // identical call changes nothing, so a runner may retry after a network461 // identical call changes nothing, so a runner may retry after a network
373 // error. To end the job use CompleteJob.462 // error. To end the job use CompleteJob.
374 //463 //
375- // Fails with invalid_argument if a rule is broken, with failed_precondition464+ // Annotations are applied with the steps, in the same atomic step: for each
376- // if a step goes back (a COMPLETED step cannot change, a step cannot go from465+ // step_number present in annotations, the annotations of that step stored
377- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail466+ // so far are replaced by the ones of the request, so a retry never
378- // if the job has ended.467+ // duplicates them. A step number absent from the request keeps its
468+ // annotations. The step of an annotation need not be in the steps of the
469+ // same call, and may already be COMPLETED: its annotations can still be
470+ // replaced (the rule that a COMPLETED step cannot change applies to
471+ // StepUpdate, not to annotations), until the job ends. A runner sends one
472+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
473+ // so replacements apply in the order of the calls.
474+ //
475+ // Fails with invalid_argument if a rule is broken (including the annotation
476+ // limits), with failed_precondition if a step goes back (a COMPLETED step
477+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
478+ // failed_precondition and a JobEnded detail if the job has ended.
379 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)479 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
380 // AppendLog appends lines to the log of a job. Needs the job token.480 // AppendLog appends lines to the log of a job. Needs the job token.
381 //481 //
@@ -480,9 +580,57 @@ type RunnerServiceHandler interface {
480 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when580 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
481 // they never started and the job did not end by cancellation).581 // they never started and the job did not end by cancellation).
482 //582 //
483- // Fails with invalid_argument if a rule is broken (including the output583+ // Annotations are applied as in UpdateJob (replacement per step number, also
484- // limits) and failed_precondition if a step goes back, as in UpdateJob.584+ // for COMPLETED steps and steps not in steps), together with the conclusion.
585+ // Summaries are not part of this call: a runner sends them with
586+ // UploadSummary before it.
587+ //
588+ // Fails with invalid_argument if a rule is broken (including the output and
589+ // annotation limits) and failed_precondition if a step goes back, as in
590+ // UpdateJob.
485 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)591 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
592+ // ResolveActions turns the "uses" of workflow and action steps into what the
593+ // runner needs to download the actions, as GitHub's action download info
594+ // does. Needs the job token; the job_id must be the one of the token. It
595+ // may be called as often as needed while the job runs (the runner calls it
596+ // once per level of composite actions, see the runner's depth limit of 9).
597+ // The runner then downloads each archive itself, from the sandbox, with the
598+ // token of the ResolvedAction when there is one.
599+ //
600+ // The response has one ResolvedAction per ActionRef, in the same order. A
601+ // reference that cannot be resolved (unknown repository, tag or branch, a
602+ // repository without access, a "uses" that GitHub itself would reject) does
603+ // not fail the call: its ResolvedAction has only ref and error, where error
604+ // is the message GitHub gives for the same failure, which the runner prints
605+ // as is. Only a failure of the call itself (credential, ended job, bad
606+ // request, server error) is an RPC error; the runner then fails the job.
607+ //
608+ // Resolution is stable for a run attempt: the same ref resolves to the same
609+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
610+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
611+ // job gets its own (ResolvedAction.token).
612+ //
613+ // Fails with unauthenticated or permission_denied as the other job RPCs,
614+ // with failed_precondition and a JobEnded detail if the job has ended, and
615+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
616+ // local action ("./path") or a Docker image ("docker://"), which the runner
617+ // handles without the server.
618+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
619+ // UploadSummary stores the job summary of one step: the Markdown that the
620+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
621+ // The runner masks it before sending it, and sends it after the step ended
622+ // and before CompleteJob.
623+ //
624+ // It is idempotent: the summary of a step is replaced by each call, so a
625+ // retry changes nothing, and an empty markdown removes the summary of the
626+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
627+ // server reads requests of up to 1 MiB plus the envelope (job id, step
628+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
629+ // their own message size limit above that.
630+ //
631+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
632+ // and with failed_precondition and a JobEnded detail if the job has ended.
633+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
486 }634 }
487 635
488 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the636 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the
@@ -534,6 +682,18 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
534 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),682 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
535 connect.WithHandlerOptions(opts...),683 connect.WithHandlerOptions(opts...),
536 )684 )
685+ runnerServiceResolveActionsHandler := connect.NewUnaryHandler(
686+ RunnerServiceResolveActionsProcedure,
687+ svc.ResolveActions,
688+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
689+ connect.WithHandlerOptions(opts...),
690+ )
691+ runnerServiceUploadSummaryHandler := connect.NewUnaryHandler(
692+ RunnerServiceUploadSummaryProcedure,
693+ svc.UploadSummary,
694+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
695+ connect.WithHandlerOptions(opts...),
696+ )
537 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {697 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
538 switch r.URL.Path {698 switch r.URL.Path {
539 case RunnerServiceRegisterRunnerProcedure:699 case RunnerServiceRegisterRunnerProcedure:
@@ -550,6 +710,10 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
550 runnerServiceWatchJobHandler.ServeHTTP(w, r)710 runnerServiceWatchJobHandler.ServeHTTP(w, r)
551 case RunnerServiceCompleteJobProcedure:711 case RunnerServiceCompleteJobProcedure:
552 runnerServiceCompleteJobHandler.ServeHTTP(w, r)712 runnerServiceCompleteJobHandler.ServeHTTP(w, r)
713+ case RunnerServiceResolveActionsProcedure:
714+ runnerServiceResolveActionsHandler.ServeHTTP(w, r)
715+ case RunnerServiceUploadSummaryProcedure:
716+ runnerServiceUploadSummaryHandler.ServeHTTP(w, r)
553 default:717 default:
554 http.NotFound(w, r)718 http.NotFound(w, r)
555 }719 }
@@ -586,3 +750,11 @@ func (UnimplementedRunnerServiceHandler) WatchJob(context.Context, *connect.Requ
586 func (UnimplementedRunnerServiceHandler) CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error) {750 func (UnimplementedRunnerServiceHandler) CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error) {
587 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.CompleteJob is not implemented"))751 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.CompleteJob is not implemented"))
588 }752 }
753+
754+func (UnimplementedRunnerServiceHandler) ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
755+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.ResolveActions is not implemented"))
756+}
757+
758+func (UnimplementedRunnerServiceHandler) UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
759+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.UploadSummary is not implemented"))
760+}
M gen/ermite/run.pb.go +550 -132 generated file: collapsed
M gen/ermite/runner.pb.go +838 -78
@@ -344,6 +344,120 @@ func (CancelReason) EnumDescriptor() ([]byte, []int) {
344344 return file_ermite_runner_proto_rawDescGZIP(), []int{4}
345345 }
346346
347+// AnnotationLevel is the severity of an annotation, with the values of
348+// GitHub's check run annotation levels ("notice", "warning", "failure"). The
349+// workflow commands ::notice, ::warning and ::error produce NOTICE, WARNING and
350+// FAILURE.
351+type AnnotationLevel int32
352+
353+const (
354+ // Not set. Rejected in requests, never returned by the server.
355+ AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED AnnotationLevel = 0
356+ // Information: ::notice.
357+ AnnotationLevel_ANNOTATION_LEVEL_NOTICE AnnotationLevel = 1
358+ // A problem that does not fail the job by itself: ::warning.
359+ AnnotationLevel_ANNOTATION_LEVEL_WARNING AnnotationLevel = 2
360+ // An error: ::error.
361+ AnnotationLevel_ANNOTATION_LEVEL_FAILURE AnnotationLevel = 3
362+)
363+
364+// Enum value maps for AnnotationLevel.
365+var (
366+ AnnotationLevel_name = map[int32]string{
367+ 0: "ANNOTATION_LEVEL_UNSPECIFIED",
368+ 1: "ANNOTATION_LEVEL_NOTICE",
369+ 2: "ANNOTATION_LEVEL_WARNING",
370+ 3: "ANNOTATION_LEVEL_FAILURE",
371+ }
372+ AnnotationLevel_value = map[string]int32{
373+ "ANNOTATION_LEVEL_UNSPECIFIED": 0,
374+ "ANNOTATION_LEVEL_NOTICE": 1,
375+ "ANNOTATION_LEVEL_WARNING": 2,
376+ "ANNOTATION_LEVEL_FAILURE": 3,
377+ }
378+)
379+
380+func (x AnnotationLevel) Enum() *AnnotationLevel {
381+ p := new(AnnotationLevel)
382+ *p = x
383+ return p
384+}
385+
386+func (x AnnotationLevel) String() string {
387+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
388+}
389+
390+func (AnnotationLevel) Descriptor() protoreflect.EnumDescriptor {
391+ return file_ermite_runner_proto_enumTypes[5].Descriptor()
392+}
393+
394+func (AnnotationLevel) Type() protoreflect.EnumType {
395+ return &file_ermite_runner_proto_enumTypes[5]
396+}
397+
398+func (x AnnotationLevel) Number() protoreflect.EnumNumber {
399+ return protoreflect.EnumNumber(x)
400+}
401+
402+// Deprecated: Use AnnotationLevel.Descriptor instead.
403+func (AnnotationLevel) EnumDescriptor() ([]byte, []int) {
404+ return file_ermite_runner_proto_rawDescGZIP(), []int{5}
405+}
406+
407+// ActionSource says where the server found an action.
408+type ActionSource int32
409+
410+const (
411+ // Not set. Only in a ResolvedAction that carries an error.
412+ ActionSource_ACTION_SOURCE_UNSPECIFIED ActionSource = 0
413+ // github.com: the archive is downloaded from GitHub, without a token.
414+ ActionSource_ACTION_SOURCE_GITHUB ActionSource = 1
415+ // A repository of this server, which wins over a github.com repository of
416+ // the same name (as GitHub Enterprise Server's own actions do).
417+ ActionSource_ACTION_SOURCE_ERMITE ActionSource = 2
418+)
419+
420+// Enum value maps for ActionSource.
421+var (
422+ ActionSource_name = map[int32]string{
423+ 0: "ACTION_SOURCE_UNSPECIFIED",
424+ 1: "ACTION_SOURCE_GITHUB",
425+ 2: "ACTION_SOURCE_ERMITE",
426+ }
427+ ActionSource_value = map[string]int32{
428+ "ACTION_SOURCE_UNSPECIFIED": 0,
429+ "ACTION_SOURCE_GITHUB": 1,
430+ "ACTION_SOURCE_ERMITE": 2,
431+ }
432+)
433+
434+func (x ActionSource) Enum() *ActionSource {
435+ p := new(ActionSource)
436+ *p = x
437+ return p
438+}
439+
440+func (x ActionSource) String() string {
441+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
442+}
443+
444+func (ActionSource) Descriptor() protoreflect.EnumDescriptor {
445+ return file_ermite_runner_proto_enumTypes[6].Descriptor()
446+}
447+
448+func (ActionSource) Type() protoreflect.EnumType {
449+ return &file_ermite_runner_proto_enumTypes[6]
450+}
451+
452+func (x ActionSource) Number() protoreflect.EnumNumber {
453+ return protoreflect.EnumNumber(x)
454+}
455+
456+// Deprecated: Use ActionSource.Descriptor instead.
457+func (ActionSource) EnumDescriptor() ([]byte, []int) {
458+ return file_ermite_runner_proto_rawDescGZIP(), []int{6}
459+}
460+
347461 // RegisterRunnerRequest describes the runner to register.
348462 type RegisterRunnerRequest struct {
349463 state protoimpl.MessageState `protogen:"open.v1"`
@@ -700,7 +814,19 @@ type Job struct {
700814 Sha string `protobuf:"bytes,13,opt,name=sha,proto3" json:"sha,omitempty"`
701815 // Ref is the full ref name that triggered the run, for example
702816 // "refs/heads/main" or "refs/tags/v1.0.0".
703- Ref string `protobuf:"bytes,14,opt,name=ref,proto3" json:"ref,omitempty"`
817+ Ref string `protobuf:"bytes,14,opt,name=ref,proto3" json:"ref,omitempty"`
818+ // GithubToken is the job repository token, the "github.token" and
819+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
820+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
821+ // the job: the runner gives it to the sandbox (actions/checkout clones with
822+ // it). It can only read the repository of the run (read-only, whatever
823+ // "permissions:" says), and is valid from the assignment until the job ends
824+ // (it is revoked then, on cancellation and when the job is lost). It is a
825+ // secret: the runner registers it in its masker before anything runs, and
826+ // neither the runner nor the server logs it. It is shown only in this
827+ // response, or in a repeat of the same poll_id; a new assignment of the same
828+ // job has a new one. Empty from servers without the feature "ci.actions".
829+ GithubToken string `protobuf:"bytes,15,opt,name=github_token,json=githubToken,proto3" json:"github_token,omitempty"`
704830 unknownFields protoimpl.UnknownFields
705831 sizeCache protoimpl.SizeCache
706832 }
@@ -833,6 +959,13 @@ func (x *Job) GetRef() string {
833959 return ""
834960 }
835961
962+func (x *Job) GetGithubToken() string {
963+ if x != nil {
964+ return x.GithubToken
965+ }
966+ return ""
967+}
968+
836969 // UpdateJobRequest reports the steps of a running job.
837970 type UpdateJobRequest struct {
838971 state protoimpl.MessageState `protogen:"open.v1"`
@@ -843,7 +976,14 @@ type UpdateJobRequest struct {
843976 // (invalid_argument beyond). Steps are numbered like GitHub's log: the
844977 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
845978 // the implicit "Complete job" is last.
846- Steps []*StepUpdate `protobuf:"bytes,2,rep,name=steps,proto3" json:"steps,omitempty"`
979+ Steps []*StepUpdate `protobuf:"bytes,2,rep,name=steps,proto3" json:"steps,omitempty"`
980+ // Annotations are the annotations of the steps that the call names: for
981+ // each step_number present, all the annotations of that step known so far,
982+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
983+ // and per step, and each one within the limits of Annotation; otherwise the
984+ // whole call is invalid_argument. The server ignores them without the
985+ // feature "ci.annotations".
986+ Annotations []*Annotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"`
847987 unknownFields protoimpl.UnknownFields
848988 sizeCache protoimpl.SizeCache
849989 }
@@ -892,6 +1032,13 @@ func (x *UpdateJobRequest) GetSteps() []*StepUpdate {
8921032 return nil
8931033 }
8941034
1035+func (x *UpdateJobRequest) GetAnnotations() []*Annotation {
1036+ if x != nil {
1037+ return x.Annotations
1038+ }
1039+ return nil
1040+}
1041+
8951042 // StepUpdate is the state of one step as the runner knows it.
8961043 type StepUpdate struct {
8971044 state protoimpl.MessageState `protogen:"open.v1"`
@@ -913,7 +1060,15 @@ type StepUpdate struct {
9131060 StartedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
9141061 // CompletedAt is when the step ended, by the clock of the runner. Required
9151062 // when state is COMPLETED.
916- CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1063+ CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1064+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
1065+ // "steps.<id>.outcome", whereas conclusion is the result after it
1066+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
1067+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
1068+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
1069+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
1070+ // (a runner that does not know the field).
1071+ Outcome CiConclusion `protobuf:"varint,7,opt,name=outcome,proto3,enum=ermite.CiConclusion" json:"outcome,omitempty"`
9171072 unknownFields protoimpl.UnknownFields
9181073 sizeCache protoimpl.SizeCache
9191074 }
@@ -990,6 +1145,13 @@ func (x *StepUpdate) GetCompletedAt() *timestamppb.Timestamp {
9901145 return nil
9911146 }
9921147
1148+func (x *StepUpdate) GetOutcome() CiConclusion {
1149+ if x != nil {
1150+ return x.Outcome
1151+ }
1152+ return CiConclusion_CI_CONCLUSION_UNSPECIFIED
1153+}
1154+
9931155 // UpdateJobResponse is empty.
9941156 type UpdateJobResponse struct {
9951157 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1054,7 +1216,12 @@ type CompleteJobRequest struct {
10541216 RunnerShutdown bool `protobuf:"varint,4,opt,name=runner_shutdown,json=runnerShutdown,proto3" json:"runner_shutdown,omitempty"`
10551217 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
10561218 // applied in the same atomic step as the conclusion.
1057- Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1219+ Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1220+ // Annotations are those of the steps that changed since the last call, with
1221+ // the rules of UpdateJobRequest.annotations (all the annotations of each
1222+ // step named). The server ignores them without the feature
1223+ // "ci.annotations".
1224+ Annotations []*Annotation `protobuf:"bytes,6,rep,name=annotations,proto3" json:"annotations,omitempty"`
10581225 unknownFields protoimpl.UnknownFields
10591226 sizeCache protoimpl.SizeCache
10601227 }
@@ -1124,6 +1291,13 @@ func (x *CompleteJobRequest) GetSteps() []*StepUpdate {
11241291 return nil
11251292 }
11261293
1294+func (x *CompleteJobRequest) GetAnnotations() []*Annotation {
1295+ if x != nil {
1296+ return x.Annotations
1297+ }
1298+ return nil
1299+}
1300+
11271301 // CompleteJobResponse is the stored result of a job.
11281302 type CompleteJobResponse struct {
11291303 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1788,6 +1962,520 @@ func (x *CancelRequest) GetRequestedAt() *timestamppb.Timestamp {
17881962 return nil
17891963 }
17901964
1965+// Annotation is a message attached to a step, and optionally to a place in a
1966+// file of the repository, like an annotation of a GitHub check run. The runner
1967+// produces them from the workflow commands ::notice, ::warning and ::error and
1968+// from problem matchers, after masking.
1969+//
1970+// Limits, checked by the server: at most 10 annotations of each level per step
1971+// (the runner sends no more: the ones beyond only reach the log, as with
1972+// GitHub). A call that breaks a limit below is rejected whole with
1973+// invalid_argument. Lengths count characters (Unicode code points), not bytes.
1974+type Annotation struct {
1975+ state protoimpl.MessageState `protogen:"open.v1"`
1976+ // Level is the severity. Required.
1977+ Level AnnotationLevel `protobuf:"varint,1,opt,name=level,proto3,enum=ermite.AnnotationLevel" json:"level,omitempty"`
1978+ // Title is the optional title, at most 255 characters. Empty when not given.
1979+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
1980+ // Message is the text. Required, not empty, at most 4,096 characters; a
1981+ // longer one is invalid_argument. The runner never sends a longer one: like
1982+ // GitHub, it only logs such an annotation.
1983+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
1984+ // File is the path the annotation is about, relative to the repository when
1985+ // the runner can tell, else as given. At most 1,024 characters. Empty when
1986+ // the annotation is not about a file.
1987+ File string `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
1988+ // StartLine is the first line, counted from 1. 0 when not given.
1989+ StartLine int32 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"`
1990+ // EndLine is the last line, counted from 1, not before start_line. 0 when
1991+ // not given.
1992+ EndLine int32 `protobuf:"varint,6,opt,name=end_line,json=endLine,proto3" json:"end_line,omitempty"`
1993+ // StartColumn is the first column, counted from 1. 0 when not given.
1994+ StartColumn int32 `protobuf:"varint,7,opt,name=start_column,json=startColumn,proto3" json:"start_column,omitempty"`
1995+ // EndColumn is the last column, counted from 1. 0 when not given.
1996+ EndColumn int32 `protobuf:"varint,8,opt,name=end_column,json=endColumn,proto3" json:"end_column,omitempty"`
1997+ // StepNumber is the number of the step that produced it (see
1998+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
1999+ // composite action belongs to the step of the workflow that uses the action.
2000+ StepNumber int32 `protobuf:"varint,9,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2001+ unknownFields protoimpl.UnknownFields
2002+ sizeCache protoimpl.SizeCache
2003+}
2004+
2005+func (x *Annotation) Reset() {
2006+ *x = Annotation{}
2007+ mi := &file_ermite_runner_proto_msgTypes[20]
2008+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2009+ ms.StoreMessageInfo(mi)
2010+}
2011+
2012+func (x *Annotation) String() string {
2013+ return protoimpl.X.MessageStringOf(x)
2014+}
2015+
2016+func (*Annotation) ProtoMessage() {}
2017+
2018+func (x *Annotation) ProtoReflect() protoreflect.Message {
2019+ mi := &file_ermite_runner_proto_msgTypes[20]
2020+ if x != nil {
2021+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2022+ if ms.LoadMessageInfo() == nil {
2023+ ms.StoreMessageInfo(mi)
2024+ }
2025+ return ms
2026+ }
2027+ return mi.MessageOf(x)
2028+}
2029+
2030+// Deprecated: Use Annotation.ProtoReflect.Descriptor instead.
2031+func (*Annotation) Descriptor() ([]byte, []int) {
2032+ return file_ermite_runner_proto_rawDescGZIP(), []int{20}
2033+}
2034+
2035+func (x *Annotation) GetLevel() AnnotationLevel {
2036+ if x != nil {
2037+ return x.Level
2038+ }
2039+ return AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED
2040+}
2041+
2042+func (x *Annotation) GetTitle() string {
2043+ if x != nil {
2044+ return x.Title
2045+ }
2046+ return ""
2047+}
2048+
2049+func (x *Annotation) GetMessage() string {
2050+ if x != nil {
2051+ return x.Message
2052+ }
2053+ return ""
2054+}
2055+
2056+func (x *Annotation) GetFile() string {
2057+ if x != nil {
2058+ return x.File
2059+ }
2060+ return ""
2061+}
2062+
2063+func (x *Annotation) GetStartLine() int32 {
2064+ if x != nil {
2065+ return x.StartLine
2066+ }
2067+ return 0
2068+}
2069+
2070+func (x *Annotation) GetEndLine() int32 {
2071+ if x != nil {
2072+ return x.EndLine
2073+ }
2074+ return 0
2075+}
2076+
2077+func (x *Annotation) GetStartColumn() int32 {
2078+ if x != nil {
2079+ return x.StartColumn
2080+ }
2081+ return 0
2082+}
2083+
2084+func (x *Annotation) GetEndColumn() int32 {
2085+ if x != nil {
2086+ return x.EndColumn
2087+ }
2088+ return 0
2089+}
2090+
2091+func (x *Annotation) GetStepNumber() int32 {
2092+ if x != nil {
2093+ return x.StepNumber
2094+ }
2095+ return 0
2096+}
2097+
2098+// ActionRef is an action to resolve.
2099+type ActionRef struct {
2100+ state protoimpl.MessageState `protogen:"open.v1"`
2101+ // Uses is the value of "uses" as written, after expression evaluation, for
2102+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
2103+ Uses string `protobuf:"bytes,1,opt,name=uses,proto3" json:"uses,omitempty"`
2104+ unknownFields protoimpl.UnknownFields
2105+ sizeCache protoimpl.SizeCache
2106+}
2107+
2108+func (x *ActionRef) Reset() {
2109+ *x = ActionRef{}
2110+ mi := &file_ermite_runner_proto_msgTypes[21]
2111+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2112+ ms.StoreMessageInfo(mi)
2113+}
2114+
2115+func (x *ActionRef) String() string {
2116+ return protoimpl.X.MessageStringOf(x)
2117+}
2118+
2119+func (*ActionRef) ProtoMessage() {}
2120+
2121+func (x *ActionRef) ProtoReflect() protoreflect.Message {
2122+ mi := &file_ermite_runner_proto_msgTypes[21]
2123+ if x != nil {
2124+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2125+ if ms.LoadMessageInfo() == nil {
2126+ ms.StoreMessageInfo(mi)
2127+ }
2128+ return ms
2129+ }
2130+ return mi.MessageOf(x)
2131+}
2132+
2133+// Deprecated: Use ActionRef.ProtoReflect.Descriptor instead.
2134+func (*ActionRef) Descriptor() ([]byte, []int) {
2135+ return file_ermite_runner_proto_rawDescGZIP(), []int{21}
2136+}
2137+
2138+func (x *ActionRef) GetUses() string {
2139+ if x != nil {
2140+ return x.Uses
2141+ }
2142+ return ""
2143+}
2144+
2145+// ResolveActionsRequest lists the actions to resolve.
2146+type ResolveActionsRequest struct {
2147+ state protoimpl.MessageState `protogen:"open.v1"`
2148+ // JobId is the Job.job_id. It must be the job of the token.
2149+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2150+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
2151+ // answered one by one.
2152+ Refs []*ActionRef `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"`
2153+ unknownFields protoimpl.UnknownFields
2154+ sizeCache protoimpl.SizeCache
2155+}
2156+
2157+func (x *ResolveActionsRequest) Reset() {
2158+ *x = ResolveActionsRequest{}
2159+ mi := &file_ermite_runner_proto_msgTypes[22]
2160+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2161+ ms.StoreMessageInfo(mi)
2162+}
2163+
2164+func (x *ResolveActionsRequest) String() string {
2165+ return protoimpl.X.MessageStringOf(x)
2166+}
2167+
2168+func (*ResolveActionsRequest) ProtoMessage() {}
2169+
2170+func (x *ResolveActionsRequest) ProtoReflect() protoreflect.Message {
2171+ mi := &file_ermite_runner_proto_msgTypes[22]
2172+ if x != nil {
2173+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2174+ if ms.LoadMessageInfo() == nil {
2175+ ms.StoreMessageInfo(mi)
2176+ }
2177+ return ms
2178+ }
2179+ return mi.MessageOf(x)
2180+}
2181+
2182+// Deprecated: Use ResolveActionsRequest.ProtoReflect.Descriptor instead.
2183+func (*ResolveActionsRequest) Descriptor() ([]byte, []int) {
2184+ return file_ermite_runner_proto_rawDescGZIP(), []int{22}
2185+}
2186+
2187+func (x *ResolveActionsRequest) GetJobId() string {
2188+ if x != nil {
2189+ return x.JobId
2190+ }
2191+ return ""
2192+}
2193+
2194+func (x *ResolveActionsRequest) GetRefs() []*ActionRef {
2195+ if x != nil {
2196+ return x.Refs
2197+ }
2198+ return nil
2199+}
2200+
2201+// ResolveActionsResponse holds the resolution of each action.
2202+type ResolveActionsResponse struct {
2203+ state protoimpl.MessageState `protogen:"open.v1"`
2204+ // Actions has one entry per ActionRef of the request, in the same order.
2205+ Actions []*ResolvedAction `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"`
2206+ unknownFields protoimpl.UnknownFields
2207+ sizeCache protoimpl.SizeCache
2208+}
2209+
2210+func (x *ResolveActionsResponse) Reset() {
2211+ *x = ResolveActionsResponse{}
2212+ mi := &file_ermite_runner_proto_msgTypes[23]
2213+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2214+ ms.StoreMessageInfo(mi)
2215+}
2216+
2217+func (x *ResolveActionsResponse) String() string {
2218+ return protoimpl.X.MessageStringOf(x)
2219+}
2220+
2221+func (*ResolveActionsResponse) ProtoMessage() {}
2222+
2223+func (x *ResolveActionsResponse) ProtoReflect() protoreflect.Message {
2224+ mi := &file_ermite_runner_proto_msgTypes[23]
2225+ if x != nil {
2226+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2227+ if ms.LoadMessageInfo() == nil {
2228+ ms.StoreMessageInfo(mi)
2229+ }
2230+ return ms
2231+ }
2232+ return mi.MessageOf(x)
2233+}
2234+
2235+// Deprecated: Use ResolveActionsResponse.ProtoReflect.Descriptor instead.
2236+func (*ResolveActionsResponse) Descriptor() ([]byte, []int) {
2237+ return file_ermite_runner_proto_rawDescGZIP(), []int{23}
2238+}
2239+
2240+func (x *ResolveActionsResponse) GetActions() []*ResolvedAction {
2241+ if x != nil {
2242+ return x.Actions
2243+ }
2244+ return nil
2245+}
2246+
2247+// ResolvedAction is where to download one action, or why it cannot be.
2248+type ResolvedAction struct {
2249+ state protoimpl.MessageState `protogen:"open.v1"`
2250+ // Ref is the ActionRef.uses of the request, unchanged.
2251+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
2252+ // NameWithOwner is the repository of the action, "owner/repo", with the
2253+ // case of the repository as the source gives it. Empty when error is set.
2254+ NameWithOwner string `protobuf:"bytes,2,opt,name=name_with_owner,json=nameWithOwner,proto3" json:"name_with_owner,omitempty"`
2255+ // Path is the sub-path of the action inside the repository, a clean
2256+ // relative path: "path/to/action" for "owner/repo/path/to/action@ref", with
2257+ // "/" separators, no leading or trailing slash, no empty, "." or ".."
2258+ // element, never absolute. Empty for an action at the root of the
2259+ // repository.
2260+ Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
2261+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
2262+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
2263+ // to, not the tag object). Stable for a run attempt: every job and every
2264+ // call of the attempt gets the same value for the same ref. Empty when error
2265+ // is set.
2266+ ResolvedSha string `protobuf:"bytes,4,opt,name=resolved_sha,json=resolvedSha,proto3" json:"resolved_sha,omitempty"`
2267+ // TarballUrl is where to download the archive of the repository at
2268+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
2269+ // runner downloads it from the sandbox. Empty when error is set.
2270+ TarballUrl string `protobuf:"bytes,5,opt,name=tarball_url,json=tarballUrl,proto3" json:"tarball_url,omitempty"`
2271+ // Token authenticates the download: the runner sends it as "Authorization:
2272+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
2273+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
2274+ // valid until the job ends, so a job can use an action of another private
2275+ // repository of the server that its own repository token cannot read. It is
2276+ // issued per job and never shared across jobs (two jobs resolving the same
2277+ // action get different tokens). It is a secret: the runner masks it, and neither the runner nor the server logs
2278+ // it.
2279+ Token string `protobuf:"bytes,6,opt,name=token,proto3" json:"token,omitempty"`
2280+ // Source is where the action was found. UNSPECIFIED when error is set.
2281+ Source ActionSource `protobuf:"varint,7,opt,name=source,proto3,enum=ermite.ActionSource" json:"source,omitempty"`
2282+ // Error is why the reference could not be resolved, in the words of GitHub
2283+ // for the same failure. Empty when the action was resolved, in which case
2284+ // the other fields describe it.
2285+ Error string `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"`
2286+ unknownFields protoimpl.UnknownFields
2287+ sizeCache protoimpl.SizeCache
2288+}
2289+
2290+func (x *ResolvedAction) Reset() {
2291+ *x = ResolvedAction{}
2292+ mi := &file_ermite_runner_proto_msgTypes[24]
2293+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2294+ ms.StoreMessageInfo(mi)
2295+}
2296+
2297+func (x *ResolvedAction) String() string {
2298+ return protoimpl.X.MessageStringOf(x)
2299+}
2300+
2301+func (*ResolvedAction) ProtoMessage() {}
2302+
2303+func (x *ResolvedAction) ProtoReflect() protoreflect.Message {
2304+ mi := &file_ermite_runner_proto_msgTypes[24]
2305+ if x != nil {
2306+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2307+ if ms.LoadMessageInfo() == nil {
2308+ ms.StoreMessageInfo(mi)
2309+ }
2310+ return ms
2311+ }
2312+ return mi.MessageOf(x)
2313+}
2314+
2315+// Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead.
2316+func (*ResolvedAction) Descriptor() ([]byte, []int) {
2317+ return file_ermite_runner_proto_rawDescGZIP(), []int{24}
2318+}
2319+
2320+func (x *ResolvedAction) GetRef() string {
2321+ if x != nil {
2322+ return x.Ref
2323+ }
2324+ return ""
2325+}
2326+
2327+func (x *ResolvedAction) GetNameWithOwner() string {
2328+ if x != nil {
2329+ return x.NameWithOwner
2330+ }
2331+ return ""
2332+}
2333+
2334+func (x *ResolvedAction) GetPath() string {
2335+ if x != nil {
2336+ return x.Path
2337+ }
2338+ return ""
2339+}
2340+
2341+func (x *ResolvedAction) GetResolvedSha() string {
2342+ if x != nil {
2343+ return x.ResolvedSha
2344+ }
2345+ return ""
2346+}
2347+
2348+func (x *ResolvedAction) GetTarballUrl() string {
2349+ if x != nil {
2350+ return x.TarballUrl
2351+ }
2352+ return ""
2353+}
2354+
2355+func (x *ResolvedAction) GetToken() string {
2356+ if x != nil {
2357+ return x.Token
2358+ }
2359+ return ""
2360+}
2361+
2362+func (x *ResolvedAction) GetSource() ActionSource {
2363+ if x != nil {
2364+ return x.Source
2365+ }
2366+ return ActionSource_ACTION_SOURCE_UNSPECIFIED
2367+}
2368+
2369+func (x *ResolvedAction) GetError() string {
2370+ if x != nil {
2371+ return x.Error
2372+ }
2373+ return ""
2374+}
2375+
2376+// UploadSummaryRequest carries the job summary of one step.
2377+type UploadSummaryRequest struct {
2378+ state protoimpl.MessageState `protogen:"open.v1"`
2379+ // JobId is the Job.job_id. It must be the job of the token.
2380+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2381+ // StepNumber is the number of the step that wrote the summary (see
2382+ // StepUpdate.number), from 1 to 1,000.
2383+ StepNumber int32 `protobuf:"varint,2,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2384+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
2385+ // bytes). Empty removes the summary of the step.
2386+ Markdown string `protobuf:"bytes,3,opt,name=markdown,proto3" json:"markdown,omitempty"`
2387+ unknownFields protoimpl.UnknownFields
2388+ sizeCache protoimpl.SizeCache
2389+}
2390+
2391+func (x *UploadSummaryRequest) Reset() {
2392+ *x = UploadSummaryRequest{}
2393+ mi := &file_ermite_runner_proto_msgTypes[25]
2394+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2395+ ms.StoreMessageInfo(mi)
2396+}
2397+
2398+func (x *UploadSummaryRequest) String() string {
2399+ return protoimpl.X.MessageStringOf(x)
2400+}
2401+
2402+func (*UploadSummaryRequest) ProtoMessage() {}
2403+
2404+func (x *UploadSummaryRequest) ProtoReflect() protoreflect.Message {
2405+ mi := &file_ermite_runner_proto_msgTypes[25]
2406+ if x != nil {
2407+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2408+ if ms.LoadMessageInfo() == nil {
2409+ ms.StoreMessageInfo(mi)
2410+ }
2411+ return ms
2412+ }
2413+ return mi.MessageOf(x)
2414+}
2415+
2416+// Deprecated: Use UploadSummaryRequest.ProtoReflect.Descriptor instead.
2417+func (*UploadSummaryRequest) Descriptor() ([]byte, []int) {
2418+ return file_ermite_runner_proto_rawDescGZIP(), []int{25}
2419+}
2420+
2421+func (x *UploadSummaryRequest) GetJobId() string {
2422+ if x != nil {
2423+ return x.JobId
2424+ }
2425+ return ""
2426+}
2427+
2428+func (x *UploadSummaryRequest) GetStepNumber() int32 {
2429+ if x != nil {
2430+ return x.StepNumber
2431+ }
2432+ return 0
2433+}
2434+
2435+func (x *UploadSummaryRequest) GetMarkdown() string {
2436+ if x != nil {
2437+ return x.Markdown
2438+ }
2439+ return ""
2440+}
2441+
2442+// UploadSummaryResponse is empty.
2443+type UploadSummaryResponse struct {
2444+ state protoimpl.MessageState `protogen:"open.v1"`
2445+ unknownFields protoimpl.UnknownFields
2446+ sizeCache protoimpl.SizeCache
2447+}
2448+
2449+func (x *UploadSummaryResponse) Reset() {
2450+ *x = UploadSummaryResponse{}
2451+ mi := &file_ermite_runner_proto_msgTypes[26]
2452+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2453+ ms.StoreMessageInfo(mi)
2454+}
2455+
2456+func (x *UploadSummaryResponse) String() string {
2457+ return protoimpl.X.MessageStringOf(x)
2458+}
2459+
2460+func (*UploadSummaryResponse) ProtoMessage() {}
2461+
2462+func (x *UploadSummaryResponse) ProtoReflect() protoreflect.Message {
2463+ mi := &file_ermite_runner_proto_msgTypes[26]
2464+ if x != nil {
2465+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2466+ if ms.LoadMessageInfo() == nil {
2467+ ms.StoreMessageInfo(mi)
2468+ }
2469+ return ms
2470+ }
2471+ return mi.MessageOf(x)
2472+}
2473+
2474+// Deprecated: Use UploadSummaryResponse.ProtoReflect.Descriptor instead.
2475+func (*UploadSummaryResponse) Descriptor() ([]byte, []int) {
2476+ return file_ermite_runner_proto_rawDescGZIP(), []int{26}
2477+}
2478+
17912479 var File_ermite_runner_proto protoreflect.FileDescriptor
17922480
17932481 const file_ermite_runner_proto_rawDesc = "" +
@@ -1810,7 +2498,7 @@ const file_ermite_runner_proto_rawDesc = "" +
18102498 "\x10FetchJobResponse\x12\x1d\n" +
18112499 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +
18122500 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +
1813- "retryAfter\"\xfa\x02\n" +
2501+ "retryAfter\"\x9d\x03\n" +
18142502 "\x03Job\x12\x15\n" +
18152503 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +
18162504 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
@@ -1826,10 +2514,12 @@ const file_ermite_runner_proto_rawDesc = "" +
18262514 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +
18272515 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +
18282516 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +
1829- "\x03ref\x18\x0e \x01(\tR\x03ref\"S\n" +
2517+ "\x03ref\x18\x0e \x01(\tR\x03ref\x12!\n" +
2518+ "\fgithub_token\x18\x0f \x01(\tR\vgithubToken\"\x89\x01\n" +
18302519 "\x10UpdateJobRequest\x12\x15\n" +
18312520 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +
1832- "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\"\x91\x02\n" +
2521+ "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2522+ "\vannotations\x18\x03 \x03(\v2\x12.ermite.AnnotationR\vannotations\"\xc1\x02\n" +
18332523 "\n" +
18342524 "StepUpdate\x12\x16\n" +
18352525 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +
@@ -1840,8 +2530,9 @@ const file_ermite_runner_proto_rawDesc = "" +
18402530 "conclusion\x129\n" +
18412531 "\n" +
18422532 "started_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +
1843- "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\"\x13\n" +
1844- "\x11UpdateJobResponse\"\xb3\x02\n" +
2533+ "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12.\n" +
2534+ "\aoutcome\x18\a \x01(\x0e2\x14.ermite.CiConclusionR\aoutcome\"\x13\n" +
2535+ "\x11UpdateJobResponse\"\xe9\x02\n" +
18452536 "\x12CompleteJobRequest\x12\x15\n" +
18462537 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +
18472538 "\n" +
@@ -1849,7 +2540,8 @@ const file_ermite_runner_proto_rawDesc = "" +
18492540 "conclusion\x12A\n" +
18502541 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +
18512542 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +
1852- "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x1a:\n" +
2543+ "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2544+ "\vannotations\x18\x06 \x03(\v2\x12.ermite.AnnotationR\vannotations\x1a:\n" +
18532545 "\fOutputsEntry\x12\x10\n" +
18542546 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
18552547 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +
@@ -1890,7 +2582,44 @@ const file_ermite_runner_proto_rawDesc = "" +
18902582 "\rCancelRequest\x12,\n" +
18912583 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +
18922584 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +
1893- "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt*o\n" +
2585+ "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt\"\x9c\x02\n" +
2586+ "\n" +
2587+ "Annotation\x12-\n" +
2588+ "\x05level\x18\x01 \x01(\x0e2\x17.ermite.AnnotationLevelR\x05level\x12\x14\n" +
2589+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x18\n" +
2590+ "\amessage\x18\x03 \x01(\tR\amessage\x12\x12\n" +
2591+ "\x04file\x18\x04 \x01(\tR\x04file\x12\x1d\n" +
2592+ "\n" +
2593+ "start_line\x18\x05 \x01(\x05R\tstartLine\x12\x19\n" +
2594+ "\bend_line\x18\x06 \x01(\x05R\aendLine\x12!\n" +
2595+ "\fstart_column\x18\a \x01(\x05R\vstartColumn\x12\x1d\n" +
2596+ "\n" +
2597+ "end_column\x18\b \x01(\x05R\tendColumn\x12\x1f\n" +
2598+ "\vstep_number\x18\t \x01(\x05R\n" +
2599+ "stepNumber\"\x1f\n" +
2600+ "\tActionRef\x12\x12\n" +
2601+ "\x04uses\x18\x01 \x01(\tR\x04uses\"U\n" +
2602+ "\x15ResolveActionsRequest\x12\x15\n" +
2603+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12%\n" +
2604+ "\x04refs\x18\x02 \x03(\v2\x11.ermite.ActionRefR\x04refs\"J\n" +
2605+ "\x16ResolveActionsResponse\x120\n" +
2606+ "\aactions\x18\x01 \x03(\v2\x16.ermite.ResolvedActionR\aactions\"\xfc\x01\n" +
2607+ "\x0eResolvedAction\x12\x10\n" +
2608+ "\x03ref\x18\x01 \x01(\tR\x03ref\x12&\n" +
2609+ "\x0fname_with_owner\x18\x02 \x01(\tR\rnameWithOwner\x12\x12\n" +
2610+ "\x04path\x18\x03 \x01(\tR\x04path\x12!\n" +
2611+ "\fresolved_sha\x18\x04 \x01(\tR\vresolvedSha\x12\x1f\n" +
2612+ "\vtarball_url\x18\x05 \x01(\tR\n" +
2613+ "tarballUrl\x12\x14\n" +
2614+ "\x05token\x18\x06 \x01(\tR\x05token\x12,\n" +
2615+ "\x06source\x18\a \x01(\x0e2\x14.ermite.ActionSourceR\x06source\x12\x14\n" +
2616+ "\x05error\x18\b \x01(\tR\x05error\"j\n" +
2617+ "\x14UploadSummaryRequest\x12\x15\n" +
2618+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
2619+ "\vstep_number\x18\x02 \x01(\x05R\n" +
2620+ "stepNumber\x12\x1a\n" +
2621+ "\bmarkdown\x18\x03 \x01(\tR\bmarkdown\"\x17\n" +
2622+ "\x15UploadSummaryResponse*o\n" +
18942623 "\bCiStatus\x12\x19\n" +
18952624 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +
18962625 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +
@@ -1919,7 +2648,16 @@ const file_ermite_runner_proto_rawDesc = "" +
19192648 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +
19202649 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +
19212650 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +
1922- "\x15CANCEL_REASON_TIMEOUT\x10\x032\xee\x03\n" +
2651+ "\x15CANCEL_REASON_TIMEOUT\x10\x03*\x8c\x01\n" +
2652+ "\x0fAnnotationLevel\x12 \n" +
2653+ "\x1cANNOTATION_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n" +
2654+ "\x17ANNOTATION_LEVEL_NOTICE\x10\x01\x12\x1c\n" +
2655+ "\x18ANNOTATION_LEVEL_WARNING\x10\x02\x12\x1c\n" +
2656+ "\x18ANNOTATION_LEVEL_FAILURE\x10\x03*a\n" +
2657+ "\fActionSource\x12\x1d\n" +
2658+ "\x19ACTION_SOURCE_UNSPECIFIED\x10\x00\x12\x18\n" +
2659+ "\x14ACTION_SOURCE_GITHUB\x10\x01\x12\x18\n" +
2660+ "\x14ACTION_SOURCE_ERMITE\x10\x022\x8d\x05\n" +
19232661 "\rRunnerService\x12O\n" +
19242662 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +
19252663 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +
@@ -1927,7 +2665,9 @@ const file_ermite_runner_proto_rawDesc = "" +
19272665 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +
19282666 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +
19292667 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +
1930- "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponseBr\n" +
2668+ "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponse\x12O\n" +
2669+ "\x0eResolveActions\x12\x1d.ermite.ResolveActionsRequest\x1a\x1e.ermite.ResolveActionsResponse\x12L\n" +
2670+ "\rUploadSummary\x12\x1c.ermite.UploadSummaryRequest\x1a\x1d.ermite.UploadSummaryResponseBr\n" +
19312671 "\n" +
19322672 "com.ermiteB\vRunnerProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
19332673
@@ -1943,78 +2683,98 @@ func file_ermite_runner_proto_rawDescGZIP() []byte {
19432683 return file_ermite_runner_proto_rawDescData
19442684 }
19452685
1946-var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
1947-var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
2686+var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
2687+var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
19482688 var file_ermite_runner_proto_goTypes = []any{
19492689 (CiStatus)(0), // 0: ermite.CiStatus
19502690 (CiConclusion)(0), // 1: ermite.CiConclusion
19512691 (StepState)(0), // 2: ermite.StepState
19522692 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation
19532693 (CancelReason)(0), // 4: ermite.CancelReason
1954- (*RegisterRunnerRequest)(nil), // 5: ermite.RegisterRunnerRequest
1955- (*RegisterRunnerResponse)(nil), // 6: ermite.RegisterRunnerResponse
1956- (*FetchJobRequest)(nil), // 7: ermite.FetchJobRequest
1957- (*FetchJobResponse)(nil), // 8: ermite.FetchJobResponse
1958- (*Job)(nil), // 9: ermite.Job
1959- (*UpdateJobRequest)(nil), // 10: ermite.UpdateJobRequest
1960- (*StepUpdate)(nil), // 11: ermite.StepUpdate
1961- (*UpdateJobResponse)(nil), // 12: ermite.UpdateJobResponse
1962- (*CompleteJobRequest)(nil), // 13: ermite.CompleteJobRequest
1963- (*CompleteJobResponse)(nil), // 14: ermite.CompleteJobResponse
1964- (*JobEnded)(nil), // 15: ermite.JobEnded
1965- (*AppendLogRequest)(nil), // 16: ermite.AppendLogRequest
1966- (*LogLine)(nil), // 17: ermite.LogLine
1967- (*AppendLogResponse)(nil), // 18: ermite.AppendLogResponse
1968- (*HeartbeatRequest)(nil), // 19: ermite.HeartbeatRequest
1969- (*HeartbeatResponse)(nil), // 20: ermite.HeartbeatResponse
1970- (*WatchJobRequest)(nil), // 21: ermite.WatchJobRequest
1971- (*WatchJobResponse)(nil), // 22: ermite.WatchJobResponse
1972- (*Keepalive)(nil), // 23: ermite.Keepalive
1973- (*CancelRequest)(nil), // 24: ermite.CancelRequest
1974- nil, // 25: ermite.CompleteJobRequest.OutputsEntry
1975- (*durationpb.Duration)(nil), // 26: google.protobuf.Duration
1976- (*timestamppb.Timestamp)(nil), // 27: google.protobuf.Timestamp
2694+ (AnnotationLevel)(0), // 5: ermite.AnnotationLevel
2695+ (ActionSource)(0), // 6: ermite.ActionSource
2696+ (*RegisterRunnerRequest)(nil), // 7: ermite.RegisterRunnerRequest
2697+ (*RegisterRunnerResponse)(nil), // 8: ermite.RegisterRunnerResponse
2698+ (*FetchJobRequest)(nil), // 9: ermite.FetchJobRequest
2699+ (*FetchJobResponse)(nil), // 10: ermite.FetchJobResponse
2700+ (*Job)(nil), // 11: ermite.Job
2701+ (*UpdateJobRequest)(nil), // 12: ermite.UpdateJobRequest
2702+ (*StepUpdate)(nil), // 13: ermite.StepUpdate
2703+ (*UpdateJobResponse)(nil), // 14: ermite.UpdateJobResponse
2704+ (*CompleteJobRequest)(nil), // 15: ermite.CompleteJobRequest
2705+ (*CompleteJobResponse)(nil), // 16: ermite.CompleteJobResponse
2706+ (*JobEnded)(nil), // 17: ermite.JobEnded
2707+ (*AppendLogRequest)(nil), // 18: ermite.AppendLogRequest
2708+ (*LogLine)(nil), // 19: ermite.LogLine
2709+ (*AppendLogResponse)(nil), // 20: ermite.AppendLogResponse
2710+ (*HeartbeatRequest)(nil), // 21: ermite.HeartbeatRequest
2711+ (*HeartbeatResponse)(nil), // 22: ermite.HeartbeatResponse
2712+ (*WatchJobRequest)(nil), // 23: ermite.WatchJobRequest
2713+ (*WatchJobResponse)(nil), // 24: ermite.WatchJobResponse
2714+ (*Keepalive)(nil), // 25: ermite.Keepalive
2715+ (*CancelRequest)(nil), // 26: ermite.CancelRequest
2716+ (*Annotation)(nil), // 27: ermite.Annotation
2717+ (*ActionRef)(nil), // 28: ermite.ActionRef
2718+ (*ResolveActionsRequest)(nil), // 29: ermite.ResolveActionsRequest
2719+ (*ResolveActionsResponse)(nil), // 30: ermite.ResolveActionsResponse
2720+ (*ResolvedAction)(nil), // 31: ermite.ResolvedAction
2721+ (*UploadSummaryRequest)(nil), // 32: ermite.UploadSummaryRequest
2722+ (*UploadSummaryResponse)(nil), // 33: ermite.UploadSummaryResponse
2723+ nil, // 34: ermite.CompleteJobRequest.OutputsEntry
2724+ (*durationpb.Duration)(nil), // 35: google.protobuf.Duration
2725+ (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp
19772726 }
19782727 var file_ermite_runner_proto_depIdxs = []int32{
19792728 3, // 0: ermite.RegisterRunnerRequest.isolation:type_name -> ermite.RunnerIsolation
1980- 9, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job
1981- 26, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration
1982- 11, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate
1983- 2, // 4: ermite.StepUpdate.state:type_name -> ermite.StepState
1984- 1, // 5: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion
1985- 27, // 6: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp
1986- 27, // 7: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp
1987- 1, // 8: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion
1988- 25, // 9: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry
1989- 11, // 10: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate
1990- 1, // 11: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion
1991- 1, // 12: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion
1992- 17, // 13: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine
1993- 27, // 14: ermite.LogLine.time:type_name -> google.protobuf.Timestamp
1994- 23, // 15: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive
1995- 24, // 16: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest
1996- 15, // 17: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded
1997- 4, // 18: ermite.CancelRequest.reason:type_name -> ermite.CancelReason
1998- 27, // 19: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp
1999- 5, // 20: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest
2000- 7, // 21: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest
2001- 10, // 22: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest
2002- 16, // 23: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest
2003- 19, // 24: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest
2004- 21, // 25: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest
2005- 13, // 26: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest
2006- 6, // 27: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse
2007- 8, // 28: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse
2008- 12, // 29: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse
2009- 18, // 30: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse
2010- 20, // 31: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse
2011- 22, // 32: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse
2012- 14, // 33: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse
2013- 27, // [27:34] is the sub-list for method output_type
2014- 20, // [20:27] is the sub-list for method input_type
2015- 20, // [20:20] is the sub-list for extension type_name
2016- 20, // [20:20] is the sub-list for extension extendee
2017- 0, // [0:20] is the sub-list for field type_name
2729+ 11, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job
2730+ 35, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration
2731+ 13, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate
2732+ 27, // 4: ermite.UpdateJobRequest.annotations:type_name -> ermite.Annotation
2733+ 2, // 5: ermite.StepUpdate.state:type_name -> ermite.StepState
2734+ 1, // 6: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion
2735+ 36, // 7: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp
2736+ 36, // 8: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp
2737+ 1, // 9: ermite.StepUpdate.outcome:type_name -> ermite.CiConclusion
2738+ 1, // 10: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion
2739+ 34, // 11: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry
2740+ 13, // 12: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate
2741+ 27, // 13: ermite.CompleteJobRequest.annotations:type_name -> ermite.Annotation
2742+ 1, // 14: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion
2743+ 1, // 15: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion
2744+ 19, // 16: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine
2745+ 36, // 17: ermite.LogLine.time:type_name -> google.protobuf.Timestamp
2746+ 25, // 18: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive
2747+ 26, // 19: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest
2748+ 17, // 20: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded
2749+ 4, // 21: ermite.CancelRequest.reason:type_name -> ermite.CancelReason
2750+ 36, // 22: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp
2751+ 5, // 23: ermite.Annotation.level:type_name -> ermite.AnnotationLevel
2752+ 28, // 24: ermite.ResolveActionsRequest.refs:type_name -> ermite.ActionRef
2753+ 31, // 25: ermite.ResolveActionsResponse.actions:type_name -> ermite.ResolvedAction
2754+ 6, // 26: ermite.ResolvedAction.source:type_name -> ermite.ActionSource
2755+ 7, // 27: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest
2756+ 9, // 28: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest
2757+ 12, // 29: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest
2758+ 18, // 30: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest
2759+ 21, // 31: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest
2760+ 23, // 32: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest
2761+ 15, // 33: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest
2762+ 29, // 34: ermite.RunnerService.ResolveActions:input_type -> ermite.ResolveActionsRequest
2763+ 32, // 35: ermite.RunnerService.UploadSummary:input_type -> ermite.UploadSummaryRequest
2764+ 8, // 36: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse
2765+ 10, // 37: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse
2766+ 14, // 38: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse
2767+ 20, // 39: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse
2768+ 22, // 40: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse
2769+ 24, // 41: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse
2770+ 16, // 42: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse
2771+ 30, // 43: ermite.RunnerService.ResolveActions:output_type -> ermite.ResolveActionsResponse
2772+ 33, // 44: ermite.RunnerService.UploadSummary:output_type -> ermite.UploadSummaryResponse
2773+ 36, // [36:45] is the sub-list for method output_type
2774+ 27, // [27:36] is the sub-list for method input_type
2775+ 27, // [27:27] is the sub-list for extension type_name
2776+ 27, // [27:27] is the sub-list for extension extendee
2777+ 0, // [0:27] is the sub-list for field type_name
20182778 }
20192779
20202780 func init() { file_ermite_runner_proto_init() }
@@ -2032,8 +2792,8 @@ func file_ermite_runner_proto_init() {
20322792 File: protoimpl.DescBuilder{
20332793 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
20342794 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),
2035- NumEnums: 5,
2036- NumMessages: 21,
2795+ NumEnums: 7,
2796+ NumMessages: 28,
20372797 NumExtensions: 0,
20382798 NumServices: 1,
20392799 },
@@ -344,6 +344,120 @@ func (CancelReason) EnumDescriptor() ([]byte, []int) {
344 return file_ermite_runner_proto_rawDescGZIP(), []int{4}344 return file_ermite_runner_proto_rawDescGZIP(), []int{4}
345 }345 }
346 346
347+// AnnotationLevel is the severity of an annotation, with the values of
348+// GitHub's check run annotation levels ("notice", "warning", "failure"). The
349+// workflow commands ::notice, ::warning and ::error produce NOTICE, WARNING and
350+// FAILURE.
351+type AnnotationLevel int32
352+
353+const (
354+ // Not set. Rejected in requests, never returned by the server.
355+ AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED AnnotationLevel = 0
356+ // Information: ::notice.
357+ AnnotationLevel_ANNOTATION_LEVEL_NOTICE AnnotationLevel = 1
358+ // A problem that does not fail the job by itself: ::warning.
359+ AnnotationLevel_ANNOTATION_LEVEL_WARNING AnnotationLevel = 2
360+ // An error: ::error.
361+ AnnotationLevel_ANNOTATION_LEVEL_FAILURE AnnotationLevel = 3
362+)
363+
364+// Enum value maps for AnnotationLevel.
365+var (
366+ AnnotationLevel_name = map[int32]string{
367+ 0: "ANNOTATION_LEVEL_UNSPECIFIED",
368+ 1: "ANNOTATION_LEVEL_NOTICE",
369+ 2: "ANNOTATION_LEVEL_WARNING",
370+ 3: "ANNOTATION_LEVEL_FAILURE",
371+ }
372+ AnnotationLevel_value = map[string]int32{
373+ "ANNOTATION_LEVEL_UNSPECIFIED": 0,
374+ "ANNOTATION_LEVEL_NOTICE": 1,
375+ "ANNOTATION_LEVEL_WARNING": 2,
376+ "ANNOTATION_LEVEL_FAILURE": 3,
377+ }
378+)
379+
380+func (x AnnotationLevel) Enum() *AnnotationLevel {
381+ p := new(AnnotationLevel)
382+ *p = x
383+ return p
384+}
385+
386+func (x AnnotationLevel) String() string {
387+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
388+}
389+
390+func (AnnotationLevel) Descriptor() protoreflect.EnumDescriptor {
391+ return file_ermite_runner_proto_enumTypes[5].Descriptor()
392+}
393+
394+func (AnnotationLevel) Type() protoreflect.EnumType {
395+ return &file_ermite_runner_proto_enumTypes[5]
396+}
397+
398+func (x AnnotationLevel) Number() protoreflect.EnumNumber {
399+ return protoreflect.EnumNumber(x)
400+}
401+
402+// Deprecated: Use AnnotationLevel.Descriptor instead.
403+func (AnnotationLevel) EnumDescriptor() ([]byte, []int) {
404+ return file_ermite_runner_proto_rawDescGZIP(), []int{5}
405+}
406+
407+// ActionSource says where the server found an action.
408+type ActionSource int32
409+
410+const (
411+ // Not set. Only in a ResolvedAction that carries an error.
412+ ActionSource_ACTION_SOURCE_UNSPECIFIED ActionSource = 0
413+ // github.com: the archive is downloaded from GitHub, without a token.
414+ ActionSource_ACTION_SOURCE_GITHUB ActionSource = 1
415+ // A repository of this server, which wins over a github.com repository of
416+ // the same name (as GitHub Enterprise Server's own actions do).
417+ ActionSource_ACTION_SOURCE_ERMITE ActionSource = 2
418+)
419+
420+// Enum value maps for ActionSource.
421+var (
422+ ActionSource_name = map[int32]string{
423+ 0: "ACTION_SOURCE_UNSPECIFIED",
424+ 1: "ACTION_SOURCE_GITHUB",
425+ 2: "ACTION_SOURCE_ERMITE",
426+ }
427+ ActionSource_value = map[string]int32{
428+ "ACTION_SOURCE_UNSPECIFIED": 0,
429+ "ACTION_SOURCE_GITHUB": 1,
430+ "ACTION_SOURCE_ERMITE": 2,
431+ }
432+)
433+
434+func (x ActionSource) Enum() *ActionSource {
435+ p := new(ActionSource)
436+ *p = x
437+ return p
438+}
439+
440+func (x ActionSource) String() string {
441+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
442+}
443+
444+func (ActionSource) Descriptor() protoreflect.EnumDescriptor {
445+ return file_ermite_runner_proto_enumTypes[6].Descriptor()
446+}
447+
448+func (ActionSource) Type() protoreflect.EnumType {
449+ return &file_ermite_runner_proto_enumTypes[6]
450+}
451+
452+func (x ActionSource) Number() protoreflect.EnumNumber {
453+ return protoreflect.EnumNumber(x)
454+}
455+
456+// Deprecated: Use ActionSource.Descriptor instead.
457+func (ActionSource) EnumDescriptor() ([]byte, []int) {
458+ return file_ermite_runner_proto_rawDescGZIP(), []int{6}
459+}
460+
347 // RegisterRunnerRequest describes the runner to register.461 // RegisterRunnerRequest describes the runner to register.
348 type RegisterRunnerRequest struct {462 type RegisterRunnerRequest struct {
349 state protoimpl.MessageState `protogen:"open.v1"`463 state protoimpl.MessageState `protogen:"open.v1"`
@@ -700,7 +814,19 @@ type Job struct {
700 Sha string `protobuf:"bytes,13,opt,name=sha,proto3" json:"sha,omitempty"`814 Sha string `protobuf:"bytes,13,opt,name=sha,proto3" json:"sha,omitempty"`
701 // Ref is the full ref name that triggered the run, for example815 // Ref is the full ref name that triggered the run, for example
702 // "refs/heads/main" or "refs/tags/v1.0.0".816 // "refs/heads/main" or "refs/tags/v1.0.0".
703- Ref string `protobuf:"bytes,14,opt,name=ref,proto3" json:"ref,omitempty"`817+ Ref string `protobuf:"bytes,14,opt,name=ref,proto3" json:"ref,omitempty"`
818+ // GithubToken is the job repository token, the "github.token" and
819+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
820+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
821+ // the job: the runner gives it to the sandbox (actions/checkout clones with
822+ // it). It can only read the repository of the run (read-only, whatever
823+ // "permissions:" says), and is valid from the assignment until the job ends
824+ // (it is revoked then, on cancellation and when the job is lost). It is a
825+ // secret: the runner registers it in its masker before anything runs, and
826+ // neither the runner nor the server logs it. It is shown only in this
827+ // response, or in a repeat of the same poll_id; a new assignment of the same
828+ // job has a new one. Empty from servers without the feature "ci.actions".
829+ GithubToken string `protobuf:"bytes,15,opt,name=github_token,json=githubToken,proto3" json:"github_token,omitempty"`
704 unknownFields protoimpl.UnknownFields830 unknownFields protoimpl.UnknownFields
705 sizeCache protoimpl.SizeCache831 sizeCache protoimpl.SizeCache
706 }832 }
@@ -833,6 +959,13 @@ func (x *Job) GetRef() string {
833 return ""959 return ""
834 }960 }
835 961
962+func (x *Job) GetGithubToken() string {
963+ if x != nil {
964+ return x.GithubToken
965+ }
966+ return ""
967+}
968+
836 // UpdateJobRequest reports the steps of a running job.969 // UpdateJobRequest reports the steps of a running job.
837 type UpdateJobRequest struct {970 type UpdateJobRequest struct {
838 state protoimpl.MessageState `protogen:"open.v1"`971 state protoimpl.MessageState `protogen:"open.v1"`
@@ -843,7 +976,14 @@ type UpdateJobRequest struct {
843 // (invalid_argument beyond). Steps are numbered like GitHub's log: the976 // (invalid_argument beyond). Steps are numbered like GitHub's log: the
844 // implicit "Set up job" is 1, the steps of the workflow follow in order, and977 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
845 // the implicit "Complete job" is last.978 // the implicit "Complete job" is last.
846- Steps []*StepUpdate `protobuf:"bytes,2,rep,name=steps,proto3" json:"steps,omitempty"`979+ Steps []*StepUpdate `protobuf:"bytes,2,rep,name=steps,proto3" json:"steps,omitempty"`
980+ // Annotations are the annotations of the steps that the call names: for
981+ // each step_number present, all the annotations of that step known so far,
982+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
983+ // and per step, and each one within the limits of Annotation; otherwise the
984+ // whole call is invalid_argument. The server ignores them without the
985+ // feature "ci.annotations".
986+ Annotations []*Annotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"`
847 unknownFields protoimpl.UnknownFields987 unknownFields protoimpl.UnknownFields
848 sizeCache protoimpl.SizeCache988 sizeCache protoimpl.SizeCache
849 }989 }
@@ -892,6 +1032,13 @@ func (x *UpdateJobRequest) GetSteps() []*StepUpdate {
892 return nil1032 return nil
893 }1033 }
894 1034
1035+func (x *UpdateJobRequest) GetAnnotations() []*Annotation {
1036+ if x != nil {
1037+ return x.Annotations
1038+ }
1039+ return nil
1040+}
1041+
895 // StepUpdate is the state of one step as the runner knows it.1042 // StepUpdate is the state of one step as the runner knows it.
896 type StepUpdate struct {1043 type StepUpdate struct {
897 state protoimpl.MessageState `protogen:"open.v1"`1044 state protoimpl.MessageState `protogen:"open.v1"`
@@ -913,7 +1060,15 @@ type StepUpdate struct {
913 StartedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`1060 StartedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
914 // CompletedAt is when the step ended, by the clock of the runner. Required1061 // CompletedAt is when the step ended, by the clock of the runner. Required
915 // when state is COMPLETED.1062 // when state is COMPLETED.
916- CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`1063+ CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1064+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
1065+ // "steps.<id>.outcome", whereas conclusion is the result after it
1066+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
1067+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
1068+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
1069+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
1070+ // (a runner that does not know the field).
1071+ Outcome CiConclusion `protobuf:"varint,7,opt,name=outcome,proto3,enum=ermite.CiConclusion" json:"outcome,omitempty"`
917 unknownFields protoimpl.UnknownFields1072 unknownFields protoimpl.UnknownFields
918 sizeCache protoimpl.SizeCache1073 sizeCache protoimpl.SizeCache
919 }1074 }
@@ -990,6 +1145,13 @@ func (x *StepUpdate) GetCompletedAt() *timestamppb.Timestamp {
990 return nil1145 return nil
991 }1146 }
992 1147
1148+func (x *StepUpdate) GetOutcome() CiConclusion {
1149+ if x != nil {
1150+ return x.Outcome
1151+ }
1152+ return CiConclusion_CI_CONCLUSION_UNSPECIFIED
1153+}
1154+
993 // UpdateJobResponse is empty.1155 // UpdateJobResponse is empty.
994 type UpdateJobResponse struct {1156 type UpdateJobResponse struct {
995 state protoimpl.MessageState `protogen:"open.v1"`1157 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1054,7 +1216,12 @@ type CompleteJobRequest struct {
1054 RunnerShutdown bool `protobuf:"varint,4,opt,name=runner_shutdown,json=runnerShutdown,proto3" json:"runner_shutdown,omitempty"`1216 RunnerShutdown bool `protobuf:"varint,4,opt,name=runner_shutdown,json=runnerShutdown,proto3" json:"runner_shutdown,omitempty"`
1055 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,1217 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
1056 // applied in the same atomic step as the conclusion.1218 // applied in the same atomic step as the conclusion.
1057- Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`1219+ Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1220+ // Annotations are those of the steps that changed since the last call, with
1221+ // the rules of UpdateJobRequest.annotations (all the annotations of each
1222+ // step named). The server ignores them without the feature
1223+ // "ci.annotations".
1224+ Annotations []*Annotation `protobuf:"bytes,6,rep,name=annotations,proto3" json:"annotations,omitempty"`
1058 unknownFields protoimpl.UnknownFields1225 unknownFields protoimpl.UnknownFields
1059 sizeCache protoimpl.SizeCache1226 sizeCache protoimpl.SizeCache
1060 }1227 }
@@ -1124,6 +1291,13 @@ func (x *CompleteJobRequest) GetSteps() []*StepUpdate {
1124 return nil1291 return nil
1125 }1292 }
1126 1293
1294+func (x *CompleteJobRequest) GetAnnotations() []*Annotation {
1295+ if x != nil {
1296+ return x.Annotations
1297+ }
1298+ return nil
1299+}
1300+
1127 // CompleteJobResponse is the stored result of a job.1301 // CompleteJobResponse is the stored result of a job.
1128 type CompleteJobResponse struct {1302 type CompleteJobResponse struct {
1129 state protoimpl.MessageState `protogen:"open.v1"`1303 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1788,6 +1962,520 @@ func (x *CancelRequest) GetRequestedAt() *timestamppb.Timestamp {
1788 return nil1962 return nil
1789 }1963 }
1790 1964
1965+// Annotation is a message attached to a step, and optionally to a place in a
1966+// file of the repository, like an annotation of a GitHub check run. The runner
1967+// produces them from the workflow commands ::notice, ::warning and ::error and
1968+// from problem matchers, after masking.
1969+//
1970+// Limits, checked by the server: at most 10 annotations of each level per step
1971+// (the runner sends no more: the ones beyond only reach the log, as with
1972+// GitHub). A call that breaks a limit below is rejected whole with
1973+// invalid_argument. Lengths count characters (Unicode code points), not bytes.
1974+type Annotation struct {
1975+ state protoimpl.MessageState `protogen:"open.v1"`
1976+ // Level is the severity. Required.
1977+ Level AnnotationLevel `protobuf:"varint,1,opt,name=level,proto3,enum=ermite.AnnotationLevel" json:"level,omitempty"`
1978+ // Title is the optional title, at most 255 characters. Empty when not given.
1979+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
1980+ // Message is the text. Required, not empty, at most 4,096 characters; a
1981+ // longer one is invalid_argument. The runner never sends a longer one: like
1982+ // GitHub, it only logs such an annotation.
1983+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
1984+ // File is the path the annotation is about, relative to the repository when
1985+ // the runner can tell, else as given. At most 1,024 characters. Empty when
1986+ // the annotation is not about a file.
1987+ File string `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
1988+ // StartLine is the first line, counted from 1. 0 when not given.
1989+ StartLine int32 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"`
1990+ // EndLine is the last line, counted from 1, not before start_line. 0 when
1991+ // not given.
1992+ EndLine int32 `protobuf:"varint,6,opt,name=end_line,json=endLine,proto3" json:"end_line,omitempty"`
1993+ // StartColumn is the first column, counted from 1. 0 when not given.
1994+ StartColumn int32 `protobuf:"varint,7,opt,name=start_column,json=startColumn,proto3" json:"start_column,omitempty"`
1995+ // EndColumn is the last column, counted from 1. 0 when not given.
1996+ EndColumn int32 `protobuf:"varint,8,opt,name=end_column,json=endColumn,proto3" json:"end_column,omitempty"`
1997+ // StepNumber is the number of the step that produced it (see
1998+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
1999+ // composite action belongs to the step of the workflow that uses the action.
2000+ StepNumber int32 `protobuf:"varint,9,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2001+ unknownFields protoimpl.UnknownFields
2002+ sizeCache protoimpl.SizeCache
2003+}
2004+
2005+func (x *Annotation) Reset() {
2006+ *x = Annotation{}
2007+ mi := &file_ermite_runner_proto_msgTypes[20]
2008+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2009+ ms.StoreMessageInfo(mi)
2010+}
2011+
2012+func (x *Annotation) String() string {
2013+ return protoimpl.X.MessageStringOf(x)
2014+}
2015+
2016+func (*Annotation) ProtoMessage() {}
2017+
2018+func (x *Annotation) ProtoReflect() protoreflect.Message {
2019+ mi := &file_ermite_runner_proto_msgTypes[20]
2020+ if x != nil {
2021+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2022+ if ms.LoadMessageInfo() == nil {
2023+ ms.StoreMessageInfo(mi)
2024+ }
2025+ return ms
2026+ }
2027+ return mi.MessageOf(x)
2028+}
2029+
2030+// Deprecated: Use Annotation.ProtoReflect.Descriptor instead.
2031+func (*Annotation) Descriptor() ([]byte, []int) {
2032+ return file_ermite_runner_proto_rawDescGZIP(), []int{20}
2033+}
2034+
2035+func (x *Annotation) GetLevel() AnnotationLevel {
2036+ if x != nil {
2037+ return x.Level
2038+ }
2039+ return AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED
2040+}
2041+
2042+func (x *Annotation) GetTitle() string {
2043+ if x != nil {
2044+ return x.Title
2045+ }
2046+ return ""
2047+}
2048+
2049+func (x *Annotation) GetMessage() string {
2050+ if x != nil {
2051+ return x.Message
2052+ }
2053+ return ""
2054+}
2055+
2056+func (x *Annotation) GetFile() string {
2057+ if x != nil {
2058+ return x.File
2059+ }
2060+ return ""
2061+}
2062+
2063+func (x *Annotation) GetStartLine() int32 {
2064+ if x != nil {
2065+ return x.StartLine
2066+ }
2067+ return 0
2068+}
2069+
2070+func (x *Annotation) GetEndLine() int32 {
2071+ if x != nil {
2072+ return x.EndLine
2073+ }
2074+ return 0
2075+}
2076+
2077+func (x *Annotation) GetStartColumn() int32 {
2078+ if x != nil {
2079+ return x.StartColumn
2080+ }
2081+ return 0
2082+}
2083+
2084+func (x *Annotation) GetEndColumn() int32 {
2085+ if x != nil {
2086+ return x.EndColumn
2087+ }
2088+ return 0
2089+}
2090+
2091+func (x *Annotation) GetStepNumber() int32 {
2092+ if x != nil {
2093+ return x.StepNumber
2094+ }
2095+ return 0
2096+}
2097+
2098+// ActionRef is an action to resolve.
2099+type ActionRef struct {
2100+ state protoimpl.MessageState `protogen:"open.v1"`
2101+ // Uses is the value of "uses" as written, after expression evaluation, for
2102+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
2103+ Uses string `protobuf:"bytes,1,opt,name=uses,proto3" json:"uses,omitempty"`
2104+ unknownFields protoimpl.UnknownFields
2105+ sizeCache protoimpl.SizeCache
2106+}
2107+
2108+func (x *ActionRef) Reset() {
2109+ *x = ActionRef{}
2110+ mi := &file_ermite_runner_proto_msgTypes[21]
2111+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2112+ ms.StoreMessageInfo(mi)
2113+}
2114+
2115+func (x *ActionRef) String() string {
2116+ return protoimpl.X.MessageStringOf(x)
2117+}
2118+
2119+func (*ActionRef) ProtoMessage() {}
2120+
2121+func (x *ActionRef) ProtoReflect() protoreflect.Message {
2122+ mi := &file_ermite_runner_proto_msgTypes[21]
2123+ if x != nil {
2124+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2125+ if ms.LoadMessageInfo() == nil {
2126+ ms.StoreMessageInfo(mi)
2127+ }
2128+ return ms
2129+ }
2130+ return mi.MessageOf(x)
2131+}
2132+
2133+// Deprecated: Use ActionRef.ProtoReflect.Descriptor instead.
2134+func (*ActionRef) Descriptor() ([]byte, []int) {
2135+ return file_ermite_runner_proto_rawDescGZIP(), []int{21}
2136+}
2137+
2138+func (x *ActionRef) GetUses() string {
2139+ if x != nil {
2140+ return x.Uses
2141+ }
2142+ return ""
2143+}
2144+
2145+// ResolveActionsRequest lists the actions to resolve.
2146+type ResolveActionsRequest struct {
2147+ state protoimpl.MessageState `protogen:"open.v1"`
2148+ // JobId is the Job.job_id. It must be the job of the token.
2149+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2150+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
2151+ // answered one by one.
2152+ Refs []*ActionRef `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"`
2153+ unknownFields protoimpl.UnknownFields
2154+ sizeCache protoimpl.SizeCache
2155+}
2156+
2157+func (x *ResolveActionsRequest) Reset() {
2158+ *x = ResolveActionsRequest{}
2159+ mi := &file_ermite_runner_proto_msgTypes[22]
2160+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2161+ ms.StoreMessageInfo(mi)
2162+}
2163+
2164+func (x *ResolveActionsRequest) String() string {
2165+ return protoimpl.X.MessageStringOf(x)
2166+}
2167+
2168+func (*ResolveActionsRequest) ProtoMessage() {}
2169+
2170+func (x *ResolveActionsRequest) ProtoReflect() protoreflect.Message {
2171+ mi := &file_ermite_runner_proto_msgTypes[22]
2172+ if x != nil {
2173+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2174+ if ms.LoadMessageInfo() == nil {
2175+ ms.StoreMessageInfo(mi)
2176+ }
2177+ return ms
2178+ }
2179+ return mi.MessageOf(x)
2180+}
2181+
2182+// Deprecated: Use ResolveActionsRequest.ProtoReflect.Descriptor instead.
2183+func (*ResolveActionsRequest) Descriptor() ([]byte, []int) {
2184+ return file_ermite_runner_proto_rawDescGZIP(), []int{22}
2185+}
2186+
2187+func (x *ResolveActionsRequest) GetJobId() string {
2188+ if x != nil {
2189+ return x.JobId
2190+ }
2191+ return ""
2192+}
2193+
2194+func (x *ResolveActionsRequest) GetRefs() []*ActionRef {
2195+ if x != nil {
2196+ return x.Refs
2197+ }
2198+ return nil
2199+}
2200+
2201+// ResolveActionsResponse holds the resolution of each action.
2202+type ResolveActionsResponse struct {
2203+ state protoimpl.MessageState `protogen:"open.v1"`
2204+ // Actions has one entry per ActionRef of the request, in the same order.
2205+ Actions []*ResolvedAction `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"`
2206+ unknownFields protoimpl.UnknownFields
2207+ sizeCache protoimpl.SizeCache
2208+}
2209+
2210+func (x *ResolveActionsResponse) Reset() {
2211+ *x = ResolveActionsResponse{}
2212+ mi := &file_ermite_runner_proto_msgTypes[23]
2213+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2214+ ms.StoreMessageInfo(mi)
2215+}
2216+
2217+func (x *ResolveActionsResponse) String() string {
2218+ return protoimpl.X.MessageStringOf(x)
2219+}
2220+
2221+func (*ResolveActionsResponse) ProtoMessage() {}
2222+
2223+func (x *ResolveActionsResponse) ProtoReflect() protoreflect.Message {
2224+ mi := &file_ermite_runner_proto_msgTypes[23]
2225+ if x != nil {
2226+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2227+ if ms.LoadMessageInfo() == nil {
2228+ ms.StoreMessageInfo(mi)
2229+ }
2230+ return ms
2231+ }
2232+ return mi.MessageOf(x)
2233+}
2234+
2235+// Deprecated: Use ResolveActionsResponse.ProtoReflect.Descriptor instead.
2236+func (*ResolveActionsResponse) Descriptor() ([]byte, []int) {
2237+ return file_ermite_runner_proto_rawDescGZIP(), []int{23}
2238+}
2239+
2240+func (x *ResolveActionsResponse) GetActions() []*ResolvedAction {
2241+ if x != nil {
2242+ return x.Actions
2243+ }
2244+ return nil
2245+}
2246+
2247+// ResolvedAction is where to download one action, or why it cannot be.
2248+type ResolvedAction struct {
2249+ state protoimpl.MessageState `protogen:"open.v1"`
2250+ // Ref is the ActionRef.uses of the request, unchanged.
2251+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
2252+ // NameWithOwner is the repository of the action, "owner/repo", with the
2253+ // case of the repository as the source gives it. Empty when error is set.
2254+ NameWithOwner string `protobuf:"bytes,2,opt,name=name_with_owner,json=nameWithOwner,proto3" json:"name_with_owner,omitempty"`
2255+ // Path is the sub-path of the action inside the repository, a clean
2256+ // relative path: "path/to/action" for "owner/repo/path/to/action@ref", with
2257+ // "/" separators, no leading or trailing slash, no empty, "." or ".."
2258+ // element, never absolute. Empty for an action at the root of the
2259+ // repository.
2260+ Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
2261+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
2262+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
2263+ // to, not the tag object). Stable for a run attempt: every job and every
2264+ // call of the attempt gets the same value for the same ref. Empty when error
2265+ // is set.
2266+ ResolvedSha string `protobuf:"bytes,4,opt,name=resolved_sha,json=resolvedSha,proto3" json:"resolved_sha,omitempty"`
2267+ // TarballUrl is where to download the archive of the repository at
2268+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
2269+ // runner downloads it from the sandbox. Empty when error is set.
2270+ TarballUrl string `protobuf:"bytes,5,opt,name=tarball_url,json=tarballUrl,proto3" json:"tarball_url,omitempty"`
2271+ // Token authenticates the download: the runner sends it as "Authorization:
2272+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
2273+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
2274+ // valid until the job ends, so a job can use an action of another private
2275+ // repository of the server that its own repository token cannot read. It is
2276+ // issued per job and never shared across jobs (two jobs resolving the same
2277+ // action get different tokens). It is a secret: the runner masks it, and neither the runner nor the server logs
2278+ // it.
2279+ Token string `protobuf:"bytes,6,opt,name=token,proto3" json:"token,omitempty"`
2280+ // Source is where the action was found. UNSPECIFIED when error is set.
2281+ Source ActionSource `protobuf:"varint,7,opt,name=source,proto3,enum=ermite.ActionSource" json:"source,omitempty"`
2282+ // Error is why the reference could not be resolved, in the words of GitHub
2283+ // for the same failure. Empty when the action was resolved, in which case
2284+ // the other fields describe it.
2285+ Error string `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"`
2286+ unknownFields protoimpl.UnknownFields
2287+ sizeCache protoimpl.SizeCache
2288+}
2289+
2290+func (x *ResolvedAction) Reset() {
2291+ *x = ResolvedAction{}
2292+ mi := &file_ermite_runner_proto_msgTypes[24]
2293+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2294+ ms.StoreMessageInfo(mi)
2295+}
2296+
2297+func (x *ResolvedAction) String() string {
2298+ return protoimpl.X.MessageStringOf(x)
2299+}
2300+
2301+func (*ResolvedAction) ProtoMessage() {}
2302+
2303+func (x *ResolvedAction) ProtoReflect() protoreflect.Message {
2304+ mi := &file_ermite_runner_proto_msgTypes[24]
2305+ if x != nil {
2306+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2307+ if ms.LoadMessageInfo() == nil {
2308+ ms.StoreMessageInfo(mi)
2309+ }
2310+ return ms
2311+ }
2312+ return mi.MessageOf(x)
2313+}
2314+
2315+// Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead.
2316+func (*ResolvedAction) Descriptor() ([]byte, []int) {
2317+ return file_ermite_runner_proto_rawDescGZIP(), []int{24}
2318+}
2319+
2320+func (x *ResolvedAction) GetRef() string {
2321+ if x != nil {
2322+ return x.Ref
2323+ }
2324+ return ""
2325+}
2326+
2327+func (x *ResolvedAction) GetNameWithOwner() string {
2328+ if x != nil {
2329+ return x.NameWithOwner
2330+ }
2331+ return ""
2332+}
2333+
2334+func (x *ResolvedAction) GetPath() string {
2335+ if x != nil {
2336+ return x.Path
2337+ }
2338+ return ""
2339+}
2340+
2341+func (x *ResolvedAction) GetResolvedSha() string {
2342+ if x != nil {
2343+ return x.ResolvedSha
2344+ }
2345+ return ""
2346+}
2347+
2348+func (x *ResolvedAction) GetTarballUrl() string {
2349+ if x != nil {
2350+ return x.TarballUrl
2351+ }
2352+ return ""
2353+}
2354+
2355+func (x *ResolvedAction) GetToken() string {
2356+ if x != nil {
2357+ return x.Token
2358+ }
2359+ return ""
2360+}
2361+
2362+func (x *ResolvedAction) GetSource() ActionSource {
2363+ if x != nil {
2364+ return x.Source
2365+ }
2366+ return ActionSource_ACTION_SOURCE_UNSPECIFIED
2367+}
2368+
2369+func (x *ResolvedAction) GetError() string {
2370+ if x != nil {
2371+ return x.Error
2372+ }
2373+ return ""
2374+}
2375+
2376+// UploadSummaryRequest carries the job summary of one step.
2377+type UploadSummaryRequest struct {
2378+ state protoimpl.MessageState `protogen:"open.v1"`
2379+ // JobId is the Job.job_id. It must be the job of the token.
2380+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2381+ // StepNumber is the number of the step that wrote the summary (see
2382+ // StepUpdate.number), from 1 to 1,000.
2383+ StepNumber int32 `protobuf:"varint,2,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2384+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
2385+ // bytes). Empty removes the summary of the step.
2386+ Markdown string `protobuf:"bytes,3,opt,name=markdown,proto3" json:"markdown,omitempty"`
2387+ unknownFields protoimpl.UnknownFields
2388+ sizeCache protoimpl.SizeCache
2389+}
2390+
2391+func (x *UploadSummaryRequest) Reset() {
2392+ *x = UploadSummaryRequest{}
2393+ mi := &file_ermite_runner_proto_msgTypes[25]
2394+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2395+ ms.StoreMessageInfo(mi)
2396+}
2397+
2398+func (x *UploadSummaryRequest) String() string {
2399+ return protoimpl.X.MessageStringOf(x)
2400+}
2401+
2402+func (*UploadSummaryRequest) ProtoMessage() {}
2403+
2404+func (x *UploadSummaryRequest) ProtoReflect() protoreflect.Message {
2405+ mi := &file_ermite_runner_proto_msgTypes[25]
2406+ if x != nil {
2407+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2408+ if ms.LoadMessageInfo() == nil {
2409+ ms.StoreMessageInfo(mi)
2410+ }
2411+ return ms
2412+ }
2413+ return mi.MessageOf(x)
2414+}
2415+
2416+// Deprecated: Use UploadSummaryRequest.ProtoReflect.Descriptor instead.
2417+func (*UploadSummaryRequest) Descriptor() ([]byte, []int) {
2418+ return file_ermite_runner_proto_rawDescGZIP(), []int{25}
2419+}
2420+
2421+func (x *UploadSummaryRequest) GetJobId() string {
2422+ if x != nil {
2423+ return x.JobId
2424+ }
2425+ return ""
2426+}
2427+
2428+func (x *UploadSummaryRequest) GetStepNumber() int32 {
2429+ if x != nil {
2430+ return x.StepNumber
2431+ }
2432+ return 0
2433+}
2434+
2435+func (x *UploadSummaryRequest) GetMarkdown() string {
2436+ if x != nil {
2437+ return x.Markdown
2438+ }
2439+ return ""
2440+}
2441+
2442+// UploadSummaryResponse is empty.
2443+type UploadSummaryResponse struct {
2444+ state protoimpl.MessageState `protogen:"open.v1"`
2445+ unknownFields protoimpl.UnknownFields
2446+ sizeCache protoimpl.SizeCache
2447+}
2448+
2449+func (x *UploadSummaryResponse) Reset() {
2450+ *x = UploadSummaryResponse{}
2451+ mi := &file_ermite_runner_proto_msgTypes[26]
2452+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2453+ ms.StoreMessageInfo(mi)
2454+}
2455+
2456+func (x *UploadSummaryResponse) String() string {
2457+ return protoimpl.X.MessageStringOf(x)
2458+}
2459+
2460+func (*UploadSummaryResponse) ProtoMessage() {}
2461+
2462+func (x *UploadSummaryResponse) ProtoReflect() protoreflect.Message {
2463+ mi := &file_ermite_runner_proto_msgTypes[26]
2464+ if x != nil {
2465+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2466+ if ms.LoadMessageInfo() == nil {
2467+ ms.StoreMessageInfo(mi)
2468+ }
2469+ return ms
2470+ }
2471+ return mi.MessageOf(x)
2472+}
2473+
2474+// Deprecated: Use UploadSummaryResponse.ProtoReflect.Descriptor instead.
2475+func (*UploadSummaryResponse) Descriptor() ([]byte, []int) {
2476+ return file_ermite_runner_proto_rawDescGZIP(), []int{26}
2477+}
2478+
1791 var File_ermite_runner_proto protoreflect.FileDescriptor2479 var File_ermite_runner_proto protoreflect.FileDescriptor
1792 2480
1793 const file_ermite_runner_proto_rawDesc = "" +2481 const file_ermite_runner_proto_rawDesc = "" +
@@ -1810,7 +2498,7 @@ const file_ermite_runner_proto_rawDesc = "" +
1810 "\x10FetchJobResponse\x12\x1d\n" +2498 "\x10FetchJobResponse\x12\x1d\n" +
1811 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +2499 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +
1812 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +2500 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +
1813- "retryAfter\"\xfa\x02\n" +2501+ "retryAfter\"\x9d\x03\n" +
1814 "\x03Job\x12\x15\n" +2502 "\x03Job\x12\x15\n" +
1815 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +2503 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +
1816 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +2504 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
@@ -1826,10 +2514,12 @@ const file_ermite_runner_proto_rawDesc = "" +
1826 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +2514 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +
1827 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +2515 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +
1828 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +2516 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +
1829- "\x03ref\x18\x0e \x01(\tR\x03ref\"S\n" +2517+ "\x03ref\x18\x0e \x01(\tR\x03ref\x12!\n" +
2518+ "\fgithub_token\x18\x0f \x01(\tR\vgithubToken\"\x89\x01\n" +
1830 "\x10UpdateJobRequest\x12\x15\n" +2519 "\x10UpdateJobRequest\x12\x15\n" +
1831 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +2520 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +
1832- "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\"\x91\x02\n" +2521+ "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2522+ "\vannotations\x18\x03 \x03(\v2\x12.ermite.AnnotationR\vannotations\"\xc1\x02\n" +
1833 "\n" +2523 "\n" +
1834 "StepUpdate\x12\x16\n" +2524 "StepUpdate\x12\x16\n" +
1835 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +2525 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +
@@ -1840,8 +2530,9 @@ const file_ermite_runner_proto_rawDesc = "" +
1840 "conclusion\x129\n" +2530 "conclusion\x129\n" +
1841 "\n" +2531 "\n" +
1842 "started_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +2532 "started_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +
1843- "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\"\x13\n" +2533+ "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12.\n" +
1844- "\x11UpdateJobResponse\"\xb3\x02\n" +2534+ "\aoutcome\x18\a \x01(\x0e2\x14.ermite.CiConclusionR\aoutcome\"\x13\n" +
2535+ "\x11UpdateJobResponse\"\xe9\x02\n" +
1845 "\x12CompleteJobRequest\x12\x15\n" +2536 "\x12CompleteJobRequest\x12\x15\n" +
1846 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +2537 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +
1847 "\n" +2538 "\n" +
@@ -1849,7 +2540,8 @@ const file_ermite_runner_proto_rawDesc = "" +
1849 "conclusion\x12A\n" +2540 "conclusion\x12A\n" +
1850 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +2541 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +
1851 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +2542 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +
1852- "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x1a:\n" +2543+ "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2544+ "\vannotations\x18\x06 \x03(\v2\x12.ermite.AnnotationR\vannotations\x1a:\n" +
1853 "\fOutputsEntry\x12\x10\n" +2545 "\fOutputsEntry\x12\x10\n" +
1854 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +2546 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
1855 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +2547 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +
@@ -1890,7 +2582,44 @@ const file_ermite_runner_proto_rawDesc = "" +
1890 "\rCancelRequest\x12,\n" +2582 "\rCancelRequest\x12,\n" +
1891 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +2583 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +
1892 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +2584 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +
1893- "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt*o\n" +2585+ "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt\"\x9c\x02\n" +
2586+ "\n" +
2587+ "Annotation\x12-\n" +
2588+ "\x05level\x18\x01 \x01(\x0e2\x17.ermite.AnnotationLevelR\x05level\x12\x14\n" +
2589+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x18\n" +
2590+ "\amessage\x18\x03 \x01(\tR\amessage\x12\x12\n" +
2591+ "\x04file\x18\x04 \x01(\tR\x04file\x12\x1d\n" +
2592+ "\n" +
2593+ "start_line\x18\x05 \x01(\x05R\tstartLine\x12\x19\n" +
2594+ "\bend_line\x18\x06 \x01(\x05R\aendLine\x12!\n" +
2595+ "\fstart_column\x18\a \x01(\x05R\vstartColumn\x12\x1d\n" +
2596+ "\n" +
2597+ "end_column\x18\b \x01(\x05R\tendColumn\x12\x1f\n" +
2598+ "\vstep_number\x18\t \x01(\x05R\n" +
2599+ "stepNumber\"\x1f\n" +
2600+ "\tActionRef\x12\x12\n" +
2601+ "\x04uses\x18\x01 \x01(\tR\x04uses\"U\n" +
2602+ "\x15ResolveActionsRequest\x12\x15\n" +
2603+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12%\n" +
2604+ "\x04refs\x18\x02 \x03(\v2\x11.ermite.ActionRefR\x04refs\"J\n" +
2605+ "\x16ResolveActionsResponse\x120\n" +
2606+ "\aactions\x18\x01 \x03(\v2\x16.ermite.ResolvedActionR\aactions\"\xfc\x01\n" +
2607+ "\x0eResolvedAction\x12\x10\n" +
2608+ "\x03ref\x18\x01 \x01(\tR\x03ref\x12&\n" +
2609+ "\x0fname_with_owner\x18\x02 \x01(\tR\rnameWithOwner\x12\x12\n" +
2610+ "\x04path\x18\x03 \x01(\tR\x04path\x12!\n" +
2611+ "\fresolved_sha\x18\x04 \x01(\tR\vresolvedSha\x12\x1f\n" +
2612+ "\vtarball_url\x18\x05 \x01(\tR\n" +
2613+ "tarballUrl\x12\x14\n" +
2614+ "\x05token\x18\x06 \x01(\tR\x05token\x12,\n" +
2615+ "\x06source\x18\a \x01(\x0e2\x14.ermite.ActionSourceR\x06source\x12\x14\n" +
2616+ "\x05error\x18\b \x01(\tR\x05error\"j\n" +
2617+ "\x14UploadSummaryRequest\x12\x15\n" +
2618+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
2619+ "\vstep_number\x18\x02 \x01(\x05R\n" +
2620+ "stepNumber\x12\x1a\n" +
2621+ "\bmarkdown\x18\x03 \x01(\tR\bmarkdown\"\x17\n" +
2622+ "\x15UploadSummaryResponse*o\n" +
1894 "\bCiStatus\x12\x19\n" +2623 "\bCiStatus\x12\x19\n" +
1895 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +2624 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +
1896 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +2625 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +
@@ -1919,7 +2648,16 @@ const file_ermite_runner_proto_rawDesc = "" +
1919 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +2648 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +
1920 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +2649 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +
1921 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +2650 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +
1922- "\x15CANCEL_REASON_TIMEOUT\x10\x032\xee\x03\n" +2651+ "\x15CANCEL_REASON_TIMEOUT\x10\x03*\x8c\x01\n" +
2652+ "\x0fAnnotationLevel\x12 \n" +
2653+ "\x1cANNOTATION_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n" +
2654+ "\x17ANNOTATION_LEVEL_NOTICE\x10\x01\x12\x1c\n" +
2655+ "\x18ANNOTATION_LEVEL_WARNING\x10\x02\x12\x1c\n" +
2656+ "\x18ANNOTATION_LEVEL_FAILURE\x10\x03*a\n" +
2657+ "\fActionSource\x12\x1d\n" +
2658+ "\x19ACTION_SOURCE_UNSPECIFIED\x10\x00\x12\x18\n" +
2659+ "\x14ACTION_SOURCE_GITHUB\x10\x01\x12\x18\n" +
2660+ "\x14ACTION_SOURCE_ERMITE\x10\x022\x8d\x05\n" +
1923 "\rRunnerService\x12O\n" +2661 "\rRunnerService\x12O\n" +
1924 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +2662 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +
1925 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +2663 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +
@@ -1927,7 +2665,9 @@ const file_ermite_runner_proto_rawDesc = "" +
1927 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +2665 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +
1928 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +2666 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +
1929 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +2667 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +
1930- "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponseBr\n" +2668+ "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponse\x12O\n" +
2669+ "\x0eResolveActions\x12\x1d.ermite.ResolveActionsRequest\x1a\x1e.ermite.ResolveActionsResponse\x12L\n" +
2670+ "\rUploadSummary\x12\x1c.ermite.UploadSummaryRequest\x1a\x1d.ermite.UploadSummaryResponseBr\n" +
1931 "\n" +2671 "\n" +
1932 "com.ermiteB\vRunnerProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"2672 "com.ermiteB\vRunnerProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
1933 2673
@@ -1943,78 +2683,98 @@ func file_ermite_runner_proto_rawDescGZIP() []byte {
1943 return file_ermite_runner_proto_rawDescData2683 return file_ermite_runner_proto_rawDescData
1944 }2684 }
1945 2685
1946-var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 5)2686+var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
1947-var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 21)2687+var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
1948 var file_ermite_runner_proto_goTypes = []any{2688 var file_ermite_runner_proto_goTypes = []any{
1949 (CiStatus)(0), // 0: ermite.CiStatus2689 (CiStatus)(0), // 0: ermite.CiStatus
1950 (CiConclusion)(0), // 1: ermite.CiConclusion2690 (CiConclusion)(0), // 1: ermite.CiConclusion
1951 (StepState)(0), // 2: ermite.StepState2691 (StepState)(0), // 2: ermite.StepState
1952 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation2692 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation
1953 (CancelReason)(0), // 4: ermite.CancelReason2693 (CancelReason)(0), // 4: ermite.CancelReason
1954- (*RegisterRunnerRequest)(nil), // 5: ermite.RegisterRunnerRequest2694+ (AnnotationLevel)(0), // 5: ermite.AnnotationLevel
1955- (*RegisterRunnerResponse)(nil), // 6: ermite.RegisterRunnerResponse2695+ (ActionSource)(0), // 6: ermite.ActionSource
1956- (*FetchJobRequest)(nil), // 7: ermite.FetchJobRequest2696+ (*RegisterRunnerRequest)(nil), // 7: ermite.RegisterRunnerRequest
1957- (*FetchJobResponse)(nil), // 8: ermite.FetchJobResponse2697+ (*RegisterRunnerResponse)(nil), // 8: ermite.RegisterRunnerResponse
1958- (*Job)(nil), // 9: ermite.Job2698+ (*FetchJobRequest)(nil), // 9: ermite.FetchJobRequest
1959- (*UpdateJobRequest)(nil), // 10: ermite.UpdateJobRequest2699+ (*FetchJobResponse)(nil), // 10: ermite.FetchJobResponse
1960- (*StepUpdate)(nil), // 11: ermite.StepUpdate2700+ (*Job)(nil), // 11: ermite.Job
1961- (*UpdateJobResponse)(nil), // 12: ermite.UpdateJobResponse2701+ (*UpdateJobRequest)(nil), // 12: ermite.UpdateJobRequest
1962- (*CompleteJobRequest)(nil), // 13: ermite.CompleteJobRequest2702+ (*StepUpdate)(nil), // 13: ermite.StepUpdate
1963- (*CompleteJobResponse)(nil), // 14: ermite.CompleteJobResponse2703+ (*UpdateJobResponse)(nil), // 14: ermite.UpdateJobResponse
1964- (*JobEnded)(nil), // 15: ermite.JobEnded2704+ (*CompleteJobRequest)(nil), // 15: ermite.CompleteJobRequest
1965- (*AppendLogRequest)(nil), // 16: ermite.AppendLogRequest2705+ (*CompleteJobResponse)(nil), // 16: ermite.CompleteJobResponse
1966- (*LogLine)(nil), // 17: ermite.LogLine2706+ (*JobEnded)(nil), // 17: ermite.JobEnded
1967- (*AppendLogResponse)(nil), // 18: ermite.AppendLogResponse2707+ (*AppendLogRequest)(nil), // 18: ermite.AppendLogRequest
1968- (*HeartbeatRequest)(nil), // 19: ermite.HeartbeatRequest2708+ (*LogLine)(nil), // 19: ermite.LogLine
1969- (*HeartbeatResponse)(nil), // 20: ermite.HeartbeatResponse2709+ (*AppendLogResponse)(nil), // 20: ermite.AppendLogResponse
1970- (*WatchJobRequest)(nil), // 21: ermite.WatchJobRequest2710+ (*HeartbeatRequest)(nil), // 21: ermite.HeartbeatRequest
1971- (*WatchJobResponse)(nil), // 22: ermite.WatchJobResponse2711+ (*HeartbeatResponse)(nil), // 22: ermite.HeartbeatResponse
1972- (*Keepalive)(nil), // 23: ermite.Keepalive2712+ (*WatchJobRequest)(nil), // 23: ermite.WatchJobRequest
1973- (*CancelRequest)(nil), // 24: ermite.CancelRequest2713+ (*WatchJobResponse)(nil), // 24: ermite.WatchJobResponse
1974- nil, // 25: ermite.CompleteJobRequest.OutputsEntry2714+ (*Keepalive)(nil), // 25: ermite.Keepalive
1975- (*durationpb.Duration)(nil), // 26: google.protobuf.Duration2715+ (*CancelRequest)(nil), // 26: ermite.CancelRequest
1976- (*timestamppb.Timestamp)(nil), // 27: google.protobuf.Timestamp2716+ (*Annotation)(nil), // 27: ermite.Annotation
2717+ (*ActionRef)(nil), // 28: ermite.ActionRef
2718+ (*ResolveActionsRequest)(nil), // 29: ermite.ResolveActionsRequest
2719+ (*ResolveActionsResponse)(nil), // 30: ermite.ResolveActionsResponse
2720+ (*ResolvedAction)(nil), // 31: ermite.ResolvedAction
2721+ (*UploadSummaryRequest)(nil), // 32: ermite.UploadSummaryRequest
2722+ (*UploadSummaryResponse)(nil), // 33: ermite.UploadSummaryResponse
2723+ nil, // 34: ermite.CompleteJobRequest.OutputsEntry
2724+ (*durationpb.Duration)(nil), // 35: google.protobuf.Duration
2725+ (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp
1977 }2726 }
1978 var file_ermite_runner_proto_depIdxs = []int32{2727 var file_ermite_runner_proto_depIdxs = []int32{
1979 3, // 0: ermite.RegisterRunnerRequest.isolation:type_name -> ermite.RunnerIsolation2728 3, // 0: ermite.RegisterRunnerRequest.isolation:type_name -> ermite.RunnerIsolation
1980- 9, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job2729+ 11, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job
1981- 26, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration2730+ 35, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration
1982- 11, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate2731+ 13, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate
1983- 2, // 4: ermite.StepUpdate.state:type_name -> ermite.StepState2732+ 27, // 4: ermite.UpdateJobRequest.annotations:type_name -> ermite.Annotation
1984- 1, // 5: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion2733+ 2, // 5: ermite.StepUpdate.state:type_name -> ermite.StepState
1985- 27, // 6: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp2734+ 1, // 6: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion
1986- 27, // 7: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp2735+ 36, // 7: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp
1987- 1, // 8: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion2736+ 36, // 8: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp
1988- 25, // 9: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry2737+ 1, // 9: ermite.StepUpdate.outcome:type_name -> ermite.CiConclusion
1989- 11, // 10: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate2738+ 1, // 10: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion
1990- 1, // 11: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion2739+ 34, // 11: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry
1991- 1, // 12: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion2740+ 13, // 12: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate
1992- 17, // 13: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine2741+ 27, // 13: ermite.CompleteJobRequest.annotations:type_name -> ermite.Annotation
1993- 27, // 14: ermite.LogLine.time:type_name -> google.protobuf.Timestamp2742+ 1, // 14: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion
1994- 23, // 15: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive2743+ 1, // 15: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion
1995- 24, // 16: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest2744+ 19, // 16: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine
1996- 15, // 17: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded2745+ 36, // 17: ermite.LogLine.time:type_name -> google.protobuf.Timestamp
1997- 4, // 18: ermite.CancelRequest.reason:type_name -> ermite.CancelReason2746+ 25, // 18: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive
1998- 27, // 19: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp2747+ 26, // 19: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest
1999- 5, // 20: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest2748+ 17, // 20: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded
2000- 7, // 21: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest2749+ 4, // 21: ermite.CancelRequest.reason:type_name -> ermite.CancelReason
2001- 10, // 22: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest2750+ 36, // 22: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp
2002- 16, // 23: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest2751+ 5, // 23: ermite.Annotation.level:type_name -> ermite.AnnotationLevel
2003- 19, // 24: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest2752+ 28, // 24: ermite.ResolveActionsRequest.refs:type_name -> ermite.ActionRef
2004- 21, // 25: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest2753+ 31, // 25: ermite.ResolveActionsResponse.actions:type_name -> ermite.ResolvedAction
2005- 13, // 26: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest2754+ 6, // 26: ermite.ResolvedAction.source:type_name -> ermite.ActionSource
2006- 6, // 27: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse2755+ 7, // 27: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest
2007- 8, // 28: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse2756+ 9, // 28: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest
2008- 12, // 29: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse2757+ 12, // 29: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest
2009- 18, // 30: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse2758+ 18, // 30: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest
2010- 20, // 31: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse2759+ 21, // 31: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest
2011- 22, // 32: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse2760+ 23, // 32: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest
2012- 14, // 33: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse2761+ 15, // 33: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest
2013- 27, // [27:34] is the sub-list for method output_type2762+ 29, // 34: ermite.RunnerService.ResolveActions:input_type -> ermite.ResolveActionsRequest
2014- 20, // [20:27] is the sub-list for method input_type2763+ 32, // 35: ermite.RunnerService.UploadSummary:input_type -> ermite.UploadSummaryRequest
2015- 20, // [20:20] is the sub-list for extension type_name2764+ 8, // 36: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse
2016- 20, // [20:20] is the sub-list for extension extendee2765+ 10, // 37: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse
2017- 0, // [0:20] is the sub-list for field type_name2766+ 14, // 38: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse
2767+ 20, // 39: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse
2768+ 22, // 40: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse
2769+ 24, // 41: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse
2770+ 16, // 42: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse
2771+ 30, // 43: ermite.RunnerService.ResolveActions:output_type -> ermite.ResolveActionsResponse
2772+ 33, // 44: ermite.RunnerService.UploadSummary:output_type -> ermite.UploadSummaryResponse
2773+ 36, // [36:45] is the sub-list for method output_type
2774+ 27, // [27:36] is the sub-list for method input_type
2775+ 27, // [27:27] is the sub-list for extension type_name
2776+ 27, // [27:27] is the sub-list for extension extendee
2777+ 0, // [0:27] is the sub-list for field type_name
2018 }2778 }
2019 2779
2020 func init() { file_ermite_runner_proto_init() }2780 func init() { file_ermite_runner_proto_init() }
@@ -2032,8 +2792,8 @@ func file_ermite_runner_proto_init() {
2032 File: protoimpl.DescBuilder{2792 File: protoimpl.DescBuilder{
2033 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),2793 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
2034 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),2794 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),
2035- NumEnums: 5,2795+ NumEnums: 7,
2036- NumMessages: 21,2796+ NumMessages: 28,
2037 NumExtensions: 0,2797 NumExtensions: 0,
2038 NumServices: 1,2798 NumServices: 1,
2039 },2799 },
M gen/ermite/server.pb.go +5 -1 generated file: collapsed
M gen_test.go +100 -0
@@ -54,10 +54,14 @@ func TestProcedures(t *testing.T) {
5454 {ermiteconnect.RunnerServiceHeartbeatProcedure, "/ermite.RunnerService/Heartbeat"},
5555 {ermiteconnect.RunnerServiceWatchJobProcedure, "/ermite.RunnerService/WatchJob"},
5656 {ermiteconnect.RunnerServiceCompleteJobProcedure, "/ermite.RunnerService/CompleteJob"},
57+ {ermiteconnect.RunnerServiceResolveActionsProcedure, "/ermite.RunnerService/ResolveActions"},
58+ {ermiteconnect.RunnerServiceUploadSummaryProcedure, "/ermite.RunnerService/UploadSummary"},
5759 {ermiteconnect.RunServiceListRunsProcedure, "/ermite.RunService/ListRuns"},
5860 {ermiteconnect.RunServiceGetRunProcedure, "/ermite.RunService/GetRun"},
5961 {ermiteconnect.RunServiceGetJobProcedure, "/ermite.RunService/GetJob"},
6062 {ermiteconnect.RunServiceGetJobLogProcedure, "/ermite.RunService/GetJobLog"},
63+ {ermiteconnect.RunServiceListAnnotationsProcedure, "/ermite.RunService/ListAnnotations"},
64+ {ermiteconnect.RunServiceGetStepSummariesProcedure, "/ermite.RunService/GetStepSummaries"},
6165 {ermiteconnect.RunServiceCancelRunProcedure, "/ermite.RunService/CancelRun"},
6266 {ermiteconnect.RunServiceRerunRunProcedure, "/ermite.RunService/RerunRun"},
6367 {ermiteconnect.RunServiceListChecksProcedure, "/ermite.RunService/ListChecks"},
@@ -120,6 +124,13 @@ func TestEnumNumbers(t *testing.T) {
120124 {"CANCEL_REASON_USER", int32(ermite.CancelReason_CANCEL_REASON_USER), 1},
121125 {"CANCEL_REASON_FAIL_FAST", int32(ermite.CancelReason_CANCEL_REASON_FAIL_FAST), 2},
122126 {"CANCEL_REASON_TIMEOUT", int32(ermite.CancelReason_CANCEL_REASON_TIMEOUT), 3},
127+ {"ANNOTATION_LEVEL_UNSPECIFIED", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED), 0},
128+ {"ANNOTATION_LEVEL_NOTICE", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_NOTICE), 1},
129+ {"ANNOTATION_LEVEL_WARNING", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_WARNING), 2},
130+ {"ANNOTATION_LEVEL_FAILURE", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_FAILURE), 3},
131+ {"ACTION_SOURCE_UNSPECIFIED", int32(ermite.ActionSource_ACTION_SOURCE_UNSPECIFIED), 0},
132+ {"ACTION_SOURCE_GITHUB", int32(ermite.ActionSource_ACTION_SOURCE_GITHUB), 1},
133+ {"ACTION_SOURCE_ERMITE", int32(ermite.ActionSource_ACTION_SOURCE_ERMITE), 2},
123134 }
124135 for _, e := range enums {
125136 if e.got != e.want {
@@ -350,3 +361,92 @@ func TestRunNameField(t *testing.T) {
350361 t.Errorf("round trip: name %q, workflow_name %q", out.GetName(), out.GetWorkflowName())
351362 }
352363 }
364+
365+// TestCI2FieldNumbers pins the numbers of the fields added for CI-2.
366+func TestCI2FieldNumbers(t *testing.T) {
367+ tests := []struct {
368+ msg proto.Message
369+ fields map[string]int
370+ }{
371+ {&ermite.Job{}, map[string]int{"github_token": 15}},
372+ {&ermite.UpdateJobRequest{}, map[string]int{"annotations": 3}},
373+ {&ermite.CompleteJobRequest{}, map[string]int{"annotations": 6}},
374+ {&ermite.StepUpdate{}, map[string]int{"outcome": 7}},
375+ {&ermite.Step{}, map[string]int{"outcome": 9}},
376+ {&ermite.Annotation{}, map[string]int{
377+ "level": 1, "title": 2, "message": 3, "file": 4, "start_line": 5,
378+ "end_line": 6, "start_column": 7, "end_column": 8, "step_number": 9,
379+ }},
380+ {&ermite.ActionRef{}, map[string]int{"uses": 1}},
381+ {&ermite.ResolveActionsRequest{}, map[string]int{"job_id": 1, "refs": 2}},
382+ {&ermite.ResolveActionsResponse{}, map[string]int{"actions": 1}},
383+ {&ermite.ResolvedAction{}, map[string]int{
384+ "ref": 1, "name_with_owner": 2, "path": 3, "resolved_sha": 4,
385+ "tarball_url": 5, "token": 6, "source": 7, "error": 8,
386+ }},
387+ {&ermite.UploadSummaryRequest{}, map[string]int{"job_id": 1, "step_number": 2, "markdown": 3}},
388+ {&ermite.ListAnnotationsRequest{}, map[string]int{"repo": 1, "run_id": 2, "attempt": 3, "job_id": 4}},
389+ {&ermite.ListAnnotationsResponse{}, map[string]int{"annotations": 1, "truncated": 2}},
390+ {&ermite.JobAnnotation{}, map[string]int{"job_id": 1, "annotation": 2}},
391+ {&ermite.GetStepSummariesRequest{}, map[string]int{"repo": 1, "job_id": 2, "attempt": 3}},
392+ {&ermite.GetStepSummariesResponse{}, map[string]int{"summaries": 1, "truncated": 2}},
393+ {&ermite.StepSummary{}, map[string]int{"step_number": 1, "markdown": 2}},
394+ }
395+ for _, tt := range tests {
396+ md := tt.msg.ProtoReflect().Descriptor()
397+ for name, num := range tt.fields {
398+ if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num {
399+ t.Errorf("%s.%s: %v, want number %d", md.Name(), name, fd, num)
400+ }
401+ }
402+ }
403+}
404+
405+// TestCI2RoundTrip checks that the CI-2 messages survive the wire.
406+func TestCI2RoundTrip(t *testing.T) {
407+ msgs := []proto.Message{
408+ &ermite.Job{JobId: "j1", GithubToken: "ermitegh_x"},
409+ &ermite.UpdateJobRequest{
410+ JobId: "j1",
411+ Steps: []*ermite.StepUpdate{{
412+ Number: 2, State: ermite.StepState_STEP_STATE_COMPLETED,
413+ Conclusion: ermite.CiConclusion_CI_CONCLUSION_SUCCESS,
414+ Outcome: ermite.CiConclusion_CI_CONCLUSION_FAILURE,
415+ }},
416+ Annotations: []*ermite.Annotation{{
417+ Level: ermite.AnnotationLevel_ANNOTATION_LEVEL_WARNING, Title: "t", Message: "m",
418+ File: "a.go", StartLine: 1, EndLine: 2, StartColumn: 3, EndColumn: 4, StepNumber: 2,
419+ }},
420+ },
421+ &ermite.CompleteJobRequest{
422+ JobId: "j1",
423+ Conclusion: ermite.CiConclusion_CI_CONCLUSION_SUCCESS,
424+ Annotations: []*ermite.Annotation{{Level: ermite.AnnotationLevel_ANNOTATION_LEVEL_FAILURE, Message: "m", StepNumber: 3}},
425+ },
426+ &ermite.ResolveActionsRequest{JobId: "j1", Refs: []*ermite.ActionRef{{Uses: "actions/checkout@v4"}, {Uses: "o/r/p@main"}}},
427+ &ermite.ResolveActionsResponse{Actions: []*ermite.ResolvedAction{
428+ {
429+ Ref: "o/r/p@main", NameWithOwner: "o/r", Path: "p", ResolvedSha: "0123456789012345678901234567890123456789",
430+ TarballUrl: "https://example.test/o/r.tar.gz", Token: "t", Source: ermite.ActionSource_ACTION_SOURCE_ERMITE,
431+ },
432+ {Ref: "x/y@z", Error: "Unable to resolve action `x/y@z`, unable to find version `z`"},
433+ }},
434+ &ermite.UploadSummaryRequest{JobId: "j1", StepNumber: 2, Markdown: "# hi"},
435+ &ermite.ListAnnotationsResponse{Annotations: []*ermite.JobAnnotation{{JobId: "j1", Annotation: &ermite.Annotation{Message: "m"}}}, Truncated: true},
436+ &ermite.GetStepSummariesResponse{Summaries: []*ermite.StepSummary{{StepNumber: 2, Markdown: "# hi"}}, Truncated: true},
437+ &ermite.RunJob{Id: "j1", Steps: []*ermite.Step{{Number: 2, Outcome: ermite.CiConclusion_CI_CONCLUSION_FAILURE}}},
438+ }
439+ for _, in := range msgs {
440+ b, err := proto.Marshal(in)
441+ if err != nil {
442+ t.Fatal(err)
443+ }
444+ out := in.ProtoReflect().New().Interface()
445+ if err := proto.Unmarshal(b, out); err != nil {
446+ t.Fatal(err)
447+ }
448+ if !proto.Equal(in, out) {
449+ t.Errorf("%T: round trip mismatch: %v != %v", in, out, in)
450+ }
451+ }
452+}
@@ -54,10 +54,14 @@ func TestProcedures(t *testing.T) {
54 {ermiteconnect.RunnerServiceHeartbeatProcedure, "/ermite.RunnerService/Heartbeat"},54 {ermiteconnect.RunnerServiceHeartbeatProcedure, "/ermite.RunnerService/Heartbeat"},
55 {ermiteconnect.RunnerServiceWatchJobProcedure, "/ermite.RunnerService/WatchJob"},55 {ermiteconnect.RunnerServiceWatchJobProcedure, "/ermite.RunnerService/WatchJob"},
56 {ermiteconnect.RunnerServiceCompleteJobProcedure, "/ermite.RunnerService/CompleteJob"},56 {ermiteconnect.RunnerServiceCompleteJobProcedure, "/ermite.RunnerService/CompleteJob"},
57+ {ermiteconnect.RunnerServiceResolveActionsProcedure, "/ermite.RunnerService/ResolveActions"},
58+ {ermiteconnect.RunnerServiceUploadSummaryProcedure, "/ermite.RunnerService/UploadSummary"},
57 {ermiteconnect.RunServiceListRunsProcedure, "/ermite.RunService/ListRuns"},59 {ermiteconnect.RunServiceListRunsProcedure, "/ermite.RunService/ListRuns"},
58 {ermiteconnect.RunServiceGetRunProcedure, "/ermite.RunService/GetRun"},60 {ermiteconnect.RunServiceGetRunProcedure, "/ermite.RunService/GetRun"},
59 {ermiteconnect.RunServiceGetJobProcedure, "/ermite.RunService/GetJob"},61 {ermiteconnect.RunServiceGetJobProcedure, "/ermite.RunService/GetJob"},
60 {ermiteconnect.RunServiceGetJobLogProcedure, "/ermite.RunService/GetJobLog"},62 {ermiteconnect.RunServiceGetJobLogProcedure, "/ermite.RunService/GetJobLog"},
63+ {ermiteconnect.RunServiceListAnnotationsProcedure, "/ermite.RunService/ListAnnotations"},
64+ {ermiteconnect.RunServiceGetStepSummariesProcedure, "/ermite.RunService/GetStepSummaries"},
61 {ermiteconnect.RunServiceCancelRunProcedure, "/ermite.RunService/CancelRun"},65 {ermiteconnect.RunServiceCancelRunProcedure, "/ermite.RunService/CancelRun"},
62 {ermiteconnect.RunServiceRerunRunProcedure, "/ermite.RunService/RerunRun"},66 {ermiteconnect.RunServiceRerunRunProcedure, "/ermite.RunService/RerunRun"},
63 {ermiteconnect.RunServiceListChecksProcedure, "/ermite.RunService/ListChecks"},67 {ermiteconnect.RunServiceListChecksProcedure, "/ermite.RunService/ListChecks"},
@@ -120,6 +124,13 @@ func TestEnumNumbers(t *testing.T) {
120 {"CANCEL_REASON_USER", int32(ermite.CancelReason_CANCEL_REASON_USER), 1},124 {"CANCEL_REASON_USER", int32(ermite.CancelReason_CANCEL_REASON_USER), 1},
121 {"CANCEL_REASON_FAIL_FAST", int32(ermite.CancelReason_CANCEL_REASON_FAIL_FAST), 2},125 {"CANCEL_REASON_FAIL_FAST", int32(ermite.CancelReason_CANCEL_REASON_FAIL_FAST), 2},
122 {"CANCEL_REASON_TIMEOUT", int32(ermite.CancelReason_CANCEL_REASON_TIMEOUT), 3},126 {"CANCEL_REASON_TIMEOUT", int32(ermite.CancelReason_CANCEL_REASON_TIMEOUT), 3},
127+ {"ANNOTATION_LEVEL_UNSPECIFIED", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED), 0},
128+ {"ANNOTATION_LEVEL_NOTICE", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_NOTICE), 1},
129+ {"ANNOTATION_LEVEL_WARNING", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_WARNING), 2},
130+ {"ANNOTATION_LEVEL_FAILURE", int32(ermite.AnnotationLevel_ANNOTATION_LEVEL_FAILURE), 3},
131+ {"ACTION_SOURCE_UNSPECIFIED", int32(ermite.ActionSource_ACTION_SOURCE_UNSPECIFIED), 0},
132+ {"ACTION_SOURCE_GITHUB", int32(ermite.ActionSource_ACTION_SOURCE_GITHUB), 1},
133+ {"ACTION_SOURCE_ERMITE", int32(ermite.ActionSource_ACTION_SOURCE_ERMITE), 2},
123 }134 }
124 for _, e := range enums {135 for _, e := range enums {
125 if e.got != e.want {136 if e.got != e.want {
@@ -350,3 +361,92 @@ func TestRunNameField(t *testing.T) {
350 t.Errorf("round trip: name %q, workflow_name %q", out.GetName(), out.GetWorkflowName())361 t.Errorf("round trip: name %q, workflow_name %q", out.GetName(), out.GetWorkflowName())
351 }362 }
352 }363 }
364+
365+// TestCI2FieldNumbers pins the numbers of the fields added for CI-2.
366+func TestCI2FieldNumbers(t *testing.T) {
367+ tests := []struct {
368+ msg proto.Message
369+ fields map[string]int
370+ }{
371+ {&ermite.Job{}, map[string]int{"github_token": 15}},
372+ {&ermite.UpdateJobRequest{}, map[string]int{"annotations": 3}},
373+ {&ermite.CompleteJobRequest{}, map[string]int{"annotations": 6}},
374+ {&ermite.StepUpdate{}, map[string]int{"outcome": 7}},
375+ {&ermite.Step{}, map[string]int{"outcome": 9}},
376+ {&ermite.Annotation{}, map[string]int{
377+ "level": 1, "title": 2, "message": 3, "file": 4, "start_line": 5,
378+ "end_line": 6, "start_column": 7, "end_column": 8, "step_number": 9,
379+ }},
380+ {&ermite.ActionRef{}, map[string]int{"uses": 1}},
381+ {&ermite.ResolveActionsRequest{}, map[string]int{"job_id": 1, "refs": 2}},
382+ {&ermite.ResolveActionsResponse{}, map[string]int{"actions": 1}},
383+ {&ermite.ResolvedAction{}, map[string]int{
384+ "ref": 1, "name_with_owner": 2, "path": 3, "resolved_sha": 4,
385+ "tarball_url": 5, "token": 6, "source": 7, "error": 8,
386+ }},
387+ {&ermite.UploadSummaryRequest{}, map[string]int{"job_id": 1, "step_number": 2, "markdown": 3}},
388+ {&ermite.ListAnnotationsRequest{}, map[string]int{"repo": 1, "run_id": 2, "attempt": 3, "job_id": 4}},
389+ {&ermite.ListAnnotationsResponse{}, map[string]int{"annotations": 1, "truncated": 2}},
390+ {&ermite.JobAnnotation{}, map[string]int{"job_id": 1, "annotation": 2}},
391+ {&ermite.GetStepSummariesRequest{}, map[string]int{"repo": 1, "job_id": 2, "attempt": 3}},
392+ {&ermite.GetStepSummariesResponse{}, map[string]int{"summaries": 1, "truncated": 2}},
393+ {&ermite.StepSummary{}, map[string]int{"step_number": 1, "markdown": 2}},
394+ }
395+ for _, tt := range tests {
396+ md := tt.msg.ProtoReflect().Descriptor()
397+ for name, num := range tt.fields {
398+ if fd := md.Fields().ByName(protoreflect.Name(name)); fd == nil || int(fd.Number()) != num {
399+ t.Errorf("%s.%s: %v, want number %d", md.Name(), name, fd, num)
400+ }
401+ }
402+ }
403+}
404+
405+// TestCI2RoundTrip checks that the CI-2 messages survive the wire.
406+func TestCI2RoundTrip(t *testing.T) {
407+ msgs := []proto.Message{
408+ &ermite.Job{JobId: "j1", GithubToken: "ermitegh_x"},
409+ &ermite.UpdateJobRequest{
410+ JobId: "j1",
411+ Steps: []*ermite.StepUpdate{{
412+ Number: 2, State: ermite.StepState_STEP_STATE_COMPLETED,
413+ Conclusion: ermite.CiConclusion_CI_CONCLUSION_SUCCESS,
414+ Outcome: ermite.CiConclusion_CI_CONCLUSION_FAILURE,
415+ }},
416+ Annotations: []*ermite.Annotation{{
417+ Level: ermite.AnnotationLevel_ANNOTATION_LEVEL_WARNING, Title: "t", Message: "m",
418+ File: "a.go", StartLine: 1, EndLine: 2, StartColumn: 3, EndColumn: 4, StepNumber: 2,
419+ }},
420+ },
421+ &ermite.CompleteJobRequest{
422+ JobId: "j1",
423+ Conclusion: ermite.CiConclusion_CI_CONCLUSION_SUCCESS,
424+ Annotations: []*ermite.Annotation{{Level: ermite.AnnotationLevel_ANNOTATION_LEVEL_FAILURE, Message: "m", StepNumber: 3}},
425+ },
426+ &ermite.ResolveActionsRequest{JobId: "j1", Refs: []*ermite.ActionRef{{Uses: "actions/checkout@v4"}, {Uses: "o/r/p@main"}}},
427+ &ermite.ResolveActionsResponse{Actions: []*ermite.ResolvedAction{
428+ {
429+ Ref: "o/r/p@main", NameWithOwner: "o/r", Path: "p", ResolvedSha: "0123456789012345678901234567890123456789",
430+ TarballUrl: "https://example.test/o/r.tar.gz", Token: "t", Source: ermite.ActionSource_ACTION_SOURCE_ERMITE,
431+ },
432+ {Ref: "x/y@z", Error: "Unable to resolve action `x/y@z`, unable to find version `z`"},
433+ }},
434+ &ermite.UploadSummaryRequest{JobId: "j1", StepNumber: 2, Markdown: "# hi"},
435+ &ermite.ListAnnotationsResponse{Annotations: []*ermite.JobAnnotation{{JobId: "j1", Annotation: &ermite.Annotation{Message: "m"}}}, Truncated: true},
436+ &ermite.GetStepSummariesResponse{Summaries: []*ermite.StepSummary{{StepNumber: 2, Markdown: "# hi"}}, Truncated: true},
437+ &ermite.RunJob{Id: "j1", Steps: []*ermite.Step{{Number: 2, Outcome: ermite.CiConclusion_CI_CONCLUSION_FAILURE}}},
438+ }
439+ for _, in := range msgs {
440+ b, err := proto.Marshal(in)
441+ if err != nil {
442+ t.Fatal(err)
443+ }
444+ out := in.ProtoReflect().New().Interface()
445+ if err := proto.Unmarshal(b, out); err != nil {
446+ t.Fatal(err)
447+ }
448+ if !proto.Equal(in, out) {
449+ t.Errorf("%T: round trip mismatch: %v != %v", in, out, in)
450+ }
451+ }
452+}
M proto/ermite/run.proto +93 -5
@@ -172,6 +172,11 @@ message Step {
172172 // IN_PROGRESS step it is the number of lines held at the time of the
173173 // call and grows; for a step without a line it equals log_start.
174174 int64 log_end = 8;
175+ // Outcome is how the step ended before continue-on-error was applied, as
176+ // StepUpdate.outcome: it differs from conclusion only for a failed step with
177+ // continue-on-error. Unset until state is COMPLETED, and for a step stored
178+ // by a server or runner before this field existed (read it as conclusion).
179+ CiConclusion outcome = 9;
175180 }
176181
177182 // Check is the result of one job on one commit, the unit shown next to a
@@ -238,9 +243,9 @@ message Runner {
238243 // RunService reads and controls CI runs, like `gh run` does on GitHub. It is for
239244 // owners and their tools; runners use RunnerService.
240245 //
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
246+// Runs, jobs, checks, logs, annotations and summaries belong to a repository,
247+// and reading them needs the same access as reading it: nothing for a public
248+// repository, the repo:read scope for a private one. A repository that does not exist or that
244249 // the caller cannot read gives not_found; so does a run or a job that belongs
245250 // to another repository than the one named (ids are global but are always
246251 // checked against the repository). Cancelling and re-running need the ci:write
@@ -255,10 +260,13 @@ message Runner {
255260 // page_token is the next_page_token of a previous response for the same
256261 // request (other fields must be unchanged).
257262 //
258-// Servers that implement the runs side (every RPC but ListRunners and
259-// RemoveRunner) list "ci.runs" in GetVersionResponse.features; those that
263+// Servers that implement the runs side (every RPC but ListRunners,
264+// RemoveRunner, ListAnnotations and GetStepSummaries) list "ci.runs" in
265+// GetVersionResponse.features; those that
260266 // implement the runners side list "ci.runners", as RunnerService does. A server
261267 // that honours the filters of ListRunsRequest also lists "ci.runs.filters".
268+// ListAnnotations needs "ci.annotations" and GetStepSummaries "ci.summaries",
269+// which are also the features of the runner side of each.
262270 service RunService {
263271 // ListRuns lists the runs of a repository, highest id (newest) first. Each
264272 // run is described by its latest attempt. The filters narrow the result; a
@@ -273,6 +281,25 @@ service RunService {
273281 // GetJob returns one job with its steps. Fails with not_found if the job
274282 // or the attempt does not exist.
275283 rpc GetJob(GetJobRequest) returns (GetJobResponse);
284+ // ListAnnotations lists the annotations of a run attempt, optionally of one
285+ // job, ordered by job (as in GetRun), step number, then the order in which
286+ // the step produced them. For each job it gives the annotations of the
287+ // attempt in which that job executed (RunJob.attempt), which is lower than
288+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
289+ // 1,000 annotations (truncated tells). A run without annotations gives an
290+ // empty list. Only servers with the feature "ci.annotations" implement it
291+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
292+ // the job does not exist, or if the job is not a job of the run.
293+ rpc ListAnnotations(ListAnnotationsRequest) returns (ListAnnotationsResponse);
294+ // GetStepSummaries returns the job summaries (the Markdown written to
295+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
296+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
297+ // steps that have one, in step order; truncated says there are more. Needs
298+ // the same access as GetJob. Only servers with the feature
299+ // "ci.summaries" implement it (unimplemented otherwise). A job without
300+ // summaries gives an empty list. Fails with not_found if the job or the
301+ // attempt does not exist.
302+ rpc GetStepSummaries(GetStepSummariesRequest) returns (GetStepSummariesResponse);
276303 // GetJobLog streams the lines of the log of a job, from a line number. The
277304 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
278305 // text each.
@@ -393,6 +420,67 @@ message GetJobResponse {
393420 RunJob job = 1;
394421 }
395422
423+// ListAnnotationsRequest selects the annotations of a run.
424+message ListAnnotationsRequest {
425+ // Repo is the repository name.
426+ string repo = 1;
427+ // RunId is the Run.id.
428+ int64 run_id = 2;
429+ // Attempt is the attempt to read. 0 means the latest, and then each job
430+ // contributes the annotations of its own RunJob.attempt (not necessarily the
431+ // latest attempt of the run, see ListAnnotations).
432+ int32 attempt = 3;
433+ // JobId restricts the result to one job (RunJob.id). Empty means every job
434+ // of the run.
435+ string job_id = 4;
436+}
437+
438+// ListAnnotationsResponse holds the annotations of a run.
439+message ListAnnotationsResponse {
440+ // Annotations are the annotations, at most 1,000.
441+ repeated JobAnnotation annotations = 1;
442+ // Truncated is true when there are more annotations than annotations holds.
443+ bool truncated = 2;
444+}
445+
446+// JobAnnotation is an annotation with the job it belongs to.
447+message JobAnnotation {
448+ // JobId is the RunJob.id of the job.
449+ string job_id = 1;
450+ // Annotation is the annotation as the runner sent it, after the server
451+ // checked it. Its step_number is the step of the job.
452+ Annotation annotation = 2;
453+}
454+
455+// GetStepSummariesRequest selects a job.
456+message GetStepSummariesRequest {
457+ // Repo is the repository name.
458+ string repo = 1;
459+ // JobId is the RunJob.id.
460+ string job_id = 2;
461+ // Attempt is the RunJob.attempt to read. 0 means the latest.
462+ int32 attempt = 3;
463+}
464+
465+// GetStepSummariesResponse holds the summaries of a job.
466+message GetStepSummariesResponse {
467+ // Summaries are the summaries of the steps that have one, ordered by step
468+ // number: at most 20, the first 20 steps having one.
469+ repeated StepSummary summaries = 1;
470+ // Truncated is true when the job has more than 20 steps with a summary and
471+ // summaries holds only the first 20.
472+ bool truncated = 2;
473+}
474+
475+// StepSummary is the job summary of one step.
476+message StepSummary {
477+ // StepNumber is the number of the step (see Step.number).
478+ int32 step_number = 1;
479+ // Markdown is the summary as uploaded, at most 1 MiB. Clients render it
480+ // safely: it is untrusted content (raw HTML and script URLs must not run).
481+ string markdown = 2;
482+}
483+
396484 // GetJobLogRequest selects the lines to stream.
397485 message GetJobLogRequest {
398486 // Repo is the repository name.
@@ -172,6 +172,11 @@ message Step {
172 // IN_PROGRESS step it is the number of lines held at the time of the172 // 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.173 // call and grows; for a step without a line it equals log_start.
174 int64 log_end = 8;174 int64 log_end = 8;
175+ // Outcome is how the step ended before continue-on-error was applied, as
176+ // StepUpdate.outcome: it differs from conclusion only for a failed step with
177+ // continue-on-error. Unset until state is COMPLETED, and for a step stored
178+ // by a server or runner before this field existed (read it as conclusion).
179+ CiConclusion outcome = 9;
175 }180 }
176 181
177 // Check is the result of one job on one commit, the unit shown next to a182 // Check is the result of one job on one commit, the unit shown next to a
@@ -238,9 +243,9 @@ message Runner {
238 // RunService reads and controls CI runs, like `gh run` does on GitHub. It is for243 // RunService reads and controls CI runs, like `gh run` does on GitHub. It is for
239 // owners and their tools; runners use RunnerService.244 // owners and their tools; runners use RunnerService.
240 //245 //
241-// Runs, jobs, checks and logs belong to a repository, and reading them needs246+// Runs, jobs, checks, logs, annotations and summaries belong to a repository,
242-// the same access as reading it: nothing for a public repository, the247+// and reading them needs the same access as reading it: nothing for a public
243-// repo:read scope for a private one. A repository that does not exist or that248+// repository, the 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 belongs249 // 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 always250 // 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:write251 // checked against the repository). Cancelling and re-running need the ci:write
@@ -255,10 +260,13 @@ message Runner {
255 // page_token is the next_page_token of a previous response for the same260 // page_token is the next_page_token of a previous response for the same
256 // request (other fields must be unchanged).261 // request (other fields must be unchanged).
257 //262 //
258-// Servers that implement the runs side (every RPC but ListRunners and263+// Servers that implement the runs side (every RPC but ListRunners,
259-// RemoveRunner) list "ci.runs" in GetVersionResponse.features; those that264+// RemoveRunner, ListAnnotations and GetStepSummaries) list "ci.runs" in
265+// GetVersionResponse.features; those that
260 // implement the runners side list "ci.runners", as RunnerService does. A server266 // implement the runners side list "ci.runners", as RunnerService does. A server
261 // that honours the filters of ListRunsRequest also lists "ci.runs.filters".267 // that honours the filters of ListRunsRequest also lists "ci.runs.filters".
268+// ListAnnotations needs "ci.annotations" and GetStepSummaries "ci.summaries",
269+// which are also the features of the runner side of each.
262 service RunService {270 service RunService {
263 // ListRuns lists the runs of a repository, highest id (newest) first. Each271 // 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; a272 // run is described by its latest attempt. The filters narrow the result; a
@@ -273,6 +281,25 @@ service RunService {
273 // GetJob returns one job with its steps. Fails with not_found if the job281 // GetJob returns one job with its steps. Fails with not_found if the job
274 // or the attempt does not exist.282 // or the attempt does not exist.
275 rpc GetJob(GetJobRequest) returns (GetJobResponse);283 rpc GetJob(GetJobRequest) returns (GetJobResponse);
284+ // ListAnnotations lists the annotations of a run attempt, optionally of one
285+ // job, ordered by job (as in GetRun), step number, then the order in which
286+ // the step produced them. For each job it gives the annotations of the
287+ // attempt in which that job executed (RunJob.attempt), which is lower than
288+ // the attempt of the run for a job kept by a re-run of failed jobs only. Needs the same access as GetRun. Returns at most
289+ // 1,000 annotations (truncated tells). A run without annotations gives an
290+ // empty list. Only servers with the feature "ci.annotations" implement it
291+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
292+ // the job does not exist, or if the job is not a job of the run.
293+ rpc ListAnnotations(ListAnnotationsRequest) returns (ListAnnotationsResponse);
294+ // GetStepSummaries returns the job summaries (the Markdown written to
295+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
296+ // number. Like GitHub, it returns at most 20 summaries per job: the first 20
297+ // steps that have one, in step order; truncated says there are more. Needs
298+ // the same access as GetJob. Only servers with the feature
299+ // "ci.summaries" implement it (unimplemented otherwise). A job without
300+ // summaries gives an empty list. Fails with not_found if the job or the
301+ // attempt does not exist.
302+ rpc GetStepSummaries(GetStepSummariesRequest) returns (GetStepSummariesResponse);
276 // GetJobLog streams the lines of the log of a job, from a line number. The303 // 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 of304 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
278 // text each.305 // text each.
@@ -393,6 +420,67 @@ message GetJobResponse {
393 RunJob job = 1;420 RunJob job = 1;
394 }421 }
395 422
423+// ListAnnotationsRequest selects the annotations of a run.
424+message ListAnnotationsRequest {
425+ // Repo is the repository name.
426+ string repo = 1;
427+ // RunId is the Run.id.
428+ int64 run_id = 2;
429+ // Attempt is the attempt to read. 0 means the latest, and then each job
430+ // contributes the annotations of its own RunJob.attempt (not necessarily the
431+ // latest attempt of the run, see ListAnnotations).
432+ int32 attempt = 3;
433+ // JobId restricts the result to one job (RunJob.id). Empty means every job
434+ // of the run.
435+ string job_id = 4;
436+}
437+
438+// ListAnnotationsResponse holds the annotations of a run.
439+message ListAnnotationsResponse {
440+ // Annotations are the annotations, at most 1,000.
441+ repeated JobAnnotation annotations = 1;
442+ // Truncated is true when there are more annotations than annotations holds.
443+ bool truncated = 2;
444+}
445+
446+// JobAnnotation is an annotation with the job it belongs to.
447+message JobAnnotation {
448+ // JobId is the RunJob.id of the job.
449+ string job_id = 1;
450+ // Annotation is the annotation as the runner sent it, after the server
451+ // checked it. Its step_number is the step of the job.
452+ Annotation annotation = 2;
453+}
454+
455+// GetStepSummariesRequest selects a job.
456+message GetStepSummariesRequest {
457+ // Repo is the repository name.
458+ string repo = 1;
459+ // JobId is the RunJob.id.
460+ string job_id = 2;
461+ // Attempt is the RunJob.attempt to read. 0 means the latest.
462+ int32 attempt = 3;
463+}
464+
465+// GetStepSummariesResponse holds the summaries of a job.
466+message GetStepSummariesResponse {
467+ // Summaries are the summaries of the steps that have one, ordered by step
468+ // number: at most 20, the first 20 steps having one.
469+ repeated StepSummary summaries = 1;
470+ // Truncated is true when the job has more than 20 steps with a summary and
471+ // summaries holds only the first 20.
472+ bool truncated = 2;
473+}
474+
475+// StepSummary is the job summary of one step.
476+message StepSummary {
477+ // StepNumber is the number of the step (see Step.number).
478+ int32 step_number = 1;
479+ // Markdown is the summary as uploaded, at most 1 MiB. Clients render it
480+ // safely: it is untrusted content (raw HTML and script URLs must not run).
481+ string markdown = 2;
482+}
483+
396 // GetJobLogRequest selects the lines to stream.484 // GetJobLogRequest selects the lines to stream.
397 message GetJobLogRequest {485 message GetJobLogRequest {
398 // Repo is the repository name.486 // Repo is the repository name.
M proto/ermite/runner.proto +251 -12
@@ -93,6 +93,32 @@ enum CancelReason {
9393 CANCEL_REASON_TIMEOUT = 3;
9494 }
9595
96+// AnnotationLevel is the severity of an annotation, with the values of
97+// GitHub's check run annotation levels ("notice", "warning", "failure"). The
98+// workflow commands ::notice, ::warning and ::error produce NOTICE, WARNING and
99+// FAILURE.
100+enum AnnotationLevel {
101+ // Not set. Rejected in requests, never returned by the server.
102+ ANNOTATION_LEVEL_UNSPECIFIED = 0;
103+ // Information: ::notice.
104+ ANNOTATION_LEVEL_NOTICE = 1;
105+ // A problem that does not fail the job by itself: ::warning.
106+ ANNOTATION_LEVEL_WARNING = 2;
107+ // An error: ::error.
108+ ANNOTATION_LEVEL_FAILURE = 3;
109+}
110+
111+// ActionSource says where the server found an action.
112+enum ActionSource {
113+ // Not set. Only in a ResolvedAction that carries an error.
114+ ACTION_SOURCE_UNSPECIFIED = 0;
115+ // github.com: the archive is downloaded from GitHub, without a token.
116+ ACTION_SOURCE_GITHUB = 1;
117+ // A repository of this server, which wins over a github.com repository of
118+ // the same name (as GitHub Enterprise Server's own actions do).
119+ ACTION_SOURCE_ERMITE = 2;
120+}
121+
96122 // RunnerService is what a CI runner (ermite-runner) calls to get jobs and
97123 // report on them. It is not for people: owners use RunService.
98124 //
@@ -104,8 +130,8 @@ enum CancelReason {
104130 // - FetchJob: the runner token returned by RegisterRunner. It identifies the
105131 // runner and only works for FetchJob. It is "ermiterun_" followed by 43
106132 // base64url characters (32 random bytes, no padding).
107-// - UpdateJob, AppendLog, Heartbeat, WatchJob, CompleteJob: the job token of
108-// the Job that FetchJob returned. It is valid for that one job and that
133+// - UpdateJob, AppendLog, Heartbeat, WatchJob, CompleteJob, ResolveActions,
134+// UploadSummary: the job token of the Job that FetchJob returned. It is valid for that one job and that
109135 // one assignment. It is "ermitejob_" followed by 43 base64url characters
110136 // (32 random bytes, no padding). The job_id of the request must be the
111137 // one of the token.
@@ -120,8 +146,8 @@ enum CancelReason {
120146 //
121147 // The end of a job. A job ends when its conclusion is set, by CompleteJob or
122148 // by the server (cancellation not honoured, lost runner, log limit, queue
123-// timeout). From then on UpdateJob, AppendLog, Heartbeat and WatchJob answer
124-// failed_precondition with a JobEnded error detail (a JobEnded message in the
149+// timeout). From then on UpdateJob, AppendLog, Heartbeat, WatchJob,
150+// ResolveActions and UploadSummary answer failed_precondition with a JobEnded error detail (a JobEnded message in the
125151 // Connect error details) that gives the conclusion; the runner stops the job
126152 // and sends nothing more. The job token is still recognised for 24 hours after
127153 // the end, so that these calls can say so and so that CompleteJob, the only
@@ -132,14 +158,22 @@ enum CancelReason {
132158 // Secrets and trust. Runner tokens and job tokens are secrets: the server
133159 // never logs them and clients must not log them. The job token stays in the
134160 // runner host process; it is never given to the sandbox that runs the job's
135-// code. A runner receives the jobs of every repository, with their workflow
161+// code. The job's repository token (Job.github_token) is another secret: it is
162+// the one the sandbox does get, and it only reads the repository of the run.
163+// A runner receives the jobs of every repository, with their workflow
136164 // files, contexts and (from CI-2) their code, and from CI-3 their secrets: the
137165 // runner:register scope therefore effectively gives read access to the code
138166 // and the secrets of every repository, private ones included. Give it only to
139167 // runners you operate.
140168 //
141169 // Servers that implement this service list "ci.runners" in
142-// GetVersionResponse.features.
170+// GetVersionResponse.features. Those that implement ResolveActions and
171+// Job.github_token also list "ci.actions", those that accept annotations
172+// (UpdateJobRequest.annotations, CompleteJobRequest.annotations) list
173+// "ci.annotations", and those that implement UploadSummary list
174+// "ci.summaries". A server without a feature ignores the fields of that
175+// feature (protobuf drops unknown fields) and answers unimplemented to its
176+// RPCs; a runner that needs one checks GetVersion first.
143177 service RunnerService {
144178 // RegisterRunner registers a runner and returns its runner token, which is
145179 // shown only in this response; the runner keeps it. The caller needs the
@@ -191,10 +225,21 @@ service RunnerService {
191225 // identical call changes nothing, so a runner may retry after a network
192226 // error. To end the job use CompleteJob.
193227 //
194- // Fails with invalid_argument if a rule is broken, with failed_precondition
195- // if a step goes back (a COMPLETED step cannot change, a step cannot go from
196- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail
197- // if the job has ended.
228+ // Annotations are applied with the steps, in the same atomic step: for each
229+ // step_number present in annotations, the annotations of that step stored
230+ // so far are replaced by the ones of the request, so a retry never
231+ // duplicates them. A step number absent from the request keeps its
232+ // annotations. The step of an annotation need not be in the steps of the
233+ // same call, and may already be COMPLETED: its annotations can still be
234+ // replaced (the rule that a COMPLETED step cannot change applies to
235+ // StepUpdate, not to annotations), until the job ends. A runner sends one
236+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
237+ // so replacements apply in the order of the calls.
238+ //
239+ // Fails with invalid_argument if a rule is broken (including the annotation
240+ // limits), with failed_precondition if a step goes back (a COMPLETED step
241+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
242+ // failed_precondition and a JobEnded detail if the job has ended.
198243 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);
199244 // AppendLog appends lines to the log of a job. Needs the job token.
200245 //
@@ -299,9 +344,57 @@ service RunnerService {
299344 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
300345 // they never started and the job did not end by cancellation).
301346 //
302- // Fails with invalid_argument if a rule is broken (including the output
303- // limits) and failed_precondition if a step goes back, as in UpdateJob.
347+ // Annotations are applied as in UpdateJob (replacement per step number, also
348+ // for COMPLETED steps and steps not in steps), together with the conclusion.
349+ // Summaries are not part of this call: a runner sends them with
350+ // UploadSummary before it.
351+ //
352+ // Fails with invalid_argument if a rule is broken (including the output and
353+ // annotation limits) and failed_precondition if a step goes back, as in
354+ // UpdateJob.
304355 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);
356+ // ResolveActions turns the "uses" of workflow and action steps into what the
357+ // runner needs to download the actions, as GitHub's action download info
358+ // does. Needs the job token; the job_id must be the one of the token. It
359+ // may be called as often as needed while the job runs (the runner calls it
360+ // once per level of composite actions, see the runner's depth limit of 9).
361+ // The runner then downloads each archive itself, from the sandbox, with the
362+ // token of the ResolvedAction when there is one.
363+ //
364+ // The response has one ResolvedAction per ActionRef, in the same order. A
365+ // reference that cannot be resolved (unknown repository, tag or branch, a
366+ // repository without access, a "uses" that GitHub itself would reject) does
367+ // not fail the call: its ResolvedAction has only ref and error, where error
368+ // is the message GitHub gives for the same failure, which the runner prints
369+ // as is. Only a failure of the call itself (credential, ended job, bad
370+ // request, server error) is an RPC error; the runner then fails the job.
371+ //
372+ // Resolution is stable for a run attempt: the same ref resolves to the same
373+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
374+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
375+ // job gets its own (ResolvedAction.token).
376+ //
377+ // Fails with unauthenticated or permission_denied as the other job RPCs,
378+ // with failed_precondition and a JobEnded detail if the job has ended, and
379+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
380+ // local action ("./path") or a Docker image ("docker://"), which the runner
381+ // handles without the server.
382+ rpc ResolveActions(ResolveActionsRequest) returns (ResolveActionsResponse);
383+ // UploadSummary stores the job summary of one step: the Markdown that the
384+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
385+ // The runner masks it before sending it, and sends it after the step ended
386+ // and before CompleteJob.
387+ //
388+ // It is idempotent: the summary of a step is replaced by each call, so a
389+ // retry changes nothing, and an empty markdown removes the summary of the
390+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
391+ // server reads requests of up to 1 MiB plus the envelope (job id, step
392+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
393+ // their own message size limit above that.
394+ //
395+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
396+ // and with failed_precondition and a JobEnded detail if the job has ended.
397+ rpc UploadSummary(UploadSummaryRequest) returns (UploadSummaryResponse);
305398 }
306399
307400 // RegisterRunnerRequest describes the runner to register.
@@ -437,6 +530,18 @@ message Job {
437530 // Ref is the full ref name that triggered the run, for example
438531 // "refs/heads/main" or "refs/tags/v1.0.0".
439532 string ref = 14;
533+ // GithubToken is the job repository token, the "github.token" and
534+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
535+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
536+ // the job: the runner gives it to the sandbox (actions/checkout clones with
537+ // it). It can only read the repository of the run (read-only, whatever
538+ // "permissions:" says), and is valid from the assignment until the job ends
539+ // (it is revoked then, on cancellation and when the job is lost). It is a
540+ // secret: the runner registers it in its masker before anything runs, and
541+ // neither the runner nor the server logs it. It is shown only in this
542+ // response, or in a repeat of the same poll_id; a new assignment of the same
543+ // job has a new one. Empty from servers without the feature "ci.actions".
544+ string github_token = 15;
440545 }
441546
442547 // UpdateJobRequest reports the steps of a running job.
@@ -449,6 +554,13 @@ message UpdateJobRequest {
449554 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
450555 // the implicit "Complete job" is last.
451556 repeated StepUpdate steps = 2;
557+ // Annotations are the annotations of the steps that the call names: for
558+ // each step_number present, all the annotations of that step known so far,
559+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
560+ // and per step, and each one within the limits of Annotation; otherwise the
561+ // whole call is invalid_argument. The server ignores them without the
562+ // feature "ci.annotations".
563+ repeated Annotation annotations = 3;
452564 }
453565
454566 // StepUpdate is the state of one step as the runner knows it.
@@ -472,6 +584,14 @@ message StepUpdate {
472584 // CompletedAt is when the step ended, by the clock of the runner. Required
473585 // when state is COMPLETED.
474586 google.protobuf.Timestamp completed_at = 6;
587+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
588+ // "steps.<id>.outcome", whereas conclusion is the result after it
589+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
590+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
591+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
592+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
593+ // (a runner that does not know the field).
594+ CiConclusion outcome = 7;
475595 }
476596
477597 // UpdateJobResponse is empty.
@@ -504,6 +624,11 @@ message CompleteJobRequest {
504624 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
505625 // applied in the same atomic step as the conclusion.
506626 repeated StepUpdate steps = 5;
627+ // Annotations are those of the steps that changed since the last call, with
628+ // the rules of UpdateJobRequest.annotations (all the annotations of each
629+ // step named). The server ignores them without the feature
630+ // "ci.annotations".
631+ repeated Annotation annotations = 6;
507632 }
508633
509634 // CompleteJobResponse is the stored result of a job.
@@ -620,3 +745,117 @@ message CancelRequest {
620745 // server.
621746 google.protobuf.Timestamp requested_at = 3;
622747 }
748+
749+// Annotation is a message attached to a step, and optionally to a place in a
750+// file of the repository, like an annotation of a GitHub check run. The runner
751+// produces them from the workflow commands ::notice, ::warning and ::error and
752+// from problem matchers, after masking.
753+//
754+// Limits, checked by the server: at most 10 annotations of each level per step
755+// (the runner sends no more: the ones beyond only reach the log, as with
756+// GitHub). A call that breaks a limit below is rejected whole with
757+// invalid_argument. Lengths count characters (Unicode code points), not bytes.
758+message Annotation {
759+ // Level is the severity. Required.
760+ AnnotationLevel level = 1;
761+ // Title is the optional title, at most 255 characters. Empty when not given.
762+ string title = 2;
763+ // Message is the text. Required, not empty, at most 4,096 characters; a
764+ // longer one is invalid_argument. The runner never sends a longer one: like
765+ // GitHub, it only logs such an annotation.
766+ string message = 3;
767+ // File is the path the annotation is about, relative to the repository when
768+ // the runner can tell, else as given. At most 1,024 characters. Empty when
769+ // the annotation is not about a file.
770+ string file = 4;
771+ // StartLine is the first line, counted from 1. 0 when not given.
772+ int32 start_line = 5;
773+ // EndLine is the last line, counted from 1, not before start_line. 0 when
774+ // not given.
775+ int32 end_line = 6;
776+ // StartColumn is the first column, counted from 1. 0 when not given.
777+ int32 start_column = 7;
778+ // EndColumn is the last column, counted from 1. 0 when not given.
779+ int32 end_column = 8;
780+ // StepNumber is the number of the step that produced it (see
781+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
782+ // composite action belongs to the step of the workflow that uses the action.
783+ int32 step_number = 9;
784+}
785+
786+// ActionRef is an action to resolve.
787+message ActionRef {
788+ // Uses is the value of "uses" as written, after expression evaluation, for
789+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
790+ string uses = 1;
791+}
792+
793+// ResolveActionsRequest lists the actions to resolve.
794+message ResolveActionsRequest {
795+ // JobId is the Job.job_id. It must be the job of the token.
796+ string job_id = 1;
797+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
798+ // answered one by one.
799+ repeated ActionRef refs = 2;
800+}
801+
802+// ResolveActionsResponse holds the resolution of each action.
803+message ResolveActionsResponse {
804+ // Actions has one entry per ActionRef of the request, in the same order.
805+ repeated ResolvedAction actions = 1;
806+}
807+
808+// ResolvedAction is where to download one action, or why it cannot be.
809+message ResolvedAction {
810+ // Ref is the ActionRef.uses of the request, unchanged.
811+ string ref = 1;
812+ // NameWithOwner is the repository of the action, "owner/repo", with the
813+ // case of the repository as the source gives it. Empty when error is set.
814+ string name_with_owner = 2;
815+ // Path is the sub-path of the action inside the repository, a clean
816+ // relative path: "path/to/action" for "owner/repo/path/to/action@ref", with
817+ // "/" separators, no leading or trailing slash, no empty, "." or ".."
818+ // element, never absolute. Empty for an action at the root of the
819+ // repository.
820+ string path = 3;
821+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
822+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
823+ // to, not the tag object). Stable for a run attempt: every job and every
824+ // call of the attempt gets the same value for the same ref. Empty when error
825+ // is set.
826+ string resolved_sha = 4;
827+ // TarballUrl is where to download the archive of the repository at
828+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
829+ // runner downloads it from the sandbox. Empty when error is set.
830+ string tarball_url = 5;
831+ // Token authenticates the download: the runner sends it as "Authorization:
832+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
833+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
834+ // valid until the job ends, so a job can use an action of another private
835+ // repository of the server that its own repository token cannot read. It is
836+ // issued per job and never shared across jobs (two jobs resolving the same
837+ // action get different tokens). It is a secret: the runner masks it, and neither the runner nor the server logs
838+ // it.
839+ string token = 6;
840+ // Source is where the action was found. UNSPECIFIED when error is set.
841+ ActionSource source = 7;
842+ // Error is why the reference could not be resolved, in the words of GitHub
843+ // for the same failure. Empty when the action was resolved, in which case
844+ // the other fields describe it.
845+ string error = 8;
846+}
847+
848+// UploadSummaryRequest carries the job summary of one step.
849+message UploadSummaryRequest {
850+ // JobId is the Job.job_id. It must be the job of the token.
851+ string job_id = 1;
852+ // StepNumber is the number of the step that wrote the summary (see
853+ // StepUpdate.number), from 1 to 1,000.
854+ int32 step_number = 2;
855+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
856+ // bytes). Empty removes the summary of the step.
857+ string markdown = 3;
858+}
859+
860+// UploadSummaryResponse is empty.
861+message UploadSummaryResponse {}
@@ -93,6 +93,32 @@ enum CancelReason {
93 CANCEL_REASON_TIMEOUT = 3;93 CANCEL_REASON_TIMEOUT = 3;
94 }94 }
95 95
96+// AnnotationLevel is the severity of an annotation, with the values of
97+// GitHub's check run annotation levels ("notice", "warning", "failure"). The
98+// workflow commands ::notice, ::warning and ::error produce NOTICE, WARNING and
99+// FAILURE.
100+enum AnnotationLevel {
101+ // Not set. Rejected in requests, never returned by the server.
102+ ANNOTATION_LEVEL_UNSPECIFIED = 0;
103+ // Information: ::notice.
104+ ANNOTATION_LEVEL_NOTICE = 1;
105+ // A problem that does not fail the job by itself: ::warning.
106+ ANNOTATION_LEVEL_WARNING = 2;
107+ // An error: ::error.
108+ ANNOTATION_LEVEL_FAILURE = 3;
109+}
110+
111+// ActionSource says where the server found an action.
112+enum ActionSource {
113+ // Not set. Only in a ResolvedAction that carries an error.
114+ ACTION_SOURCE_UNSPECIFIED = 0;
115+ // github.com: the archive is downloaded from GitHub, without a token.
116+ ACTION_SOURCE_GITHUB = 1;
117+ // A repository of this server, which wins over a github.com repository of
118+ // the same name (as GitHub Enterprise Server's own actions do).
119+ ACTION_SOURCE_ERMITE = 2;
120+}
121+
96 // RunnerService is what a CI runner (ermite-runner) calls to get jobs and122 // RunnerService is what a CI runner (ermite-runner) calls to get jobs and
97 // report on them. It is not for people: owners use RunService.123 // report on them. It is not for people: owners use RunService.
98 //124 //
@@ -104,8 +130,8 @@ enum CancelReason {
104 // - FetchJob: the runner token returned by RegisterRunner. It identifies the130 // - FetchJob: the runner token returned by RegisterRunner. It identifies the
105 // runner and only works for FetchJob. It is "ermiterun_" followed by 43131 // runner and only works for FetchJob. It is "ermiterun_" followed by 43
106 // base64url characters (32 random bytes, no padding).132 // base64url characters (32 random bytes, no padding).
107-// - UpdateJob, AppendLog, Heartbeat, WatchJob, CompleteJob: the job token of133+// - UpdateJob, AppendLog, Heartbeat, WatchJob, CompleteJob, ResolveActions,
108-// the Job that FetchJob returned. It is valid for that one job and that134+// UploadSummary: the job token of the Job that FetchJob returned. It is valid for that one job and that
109 // one assignment. It is "ermitejob_" followed by 43 base64url characters135 // one assignment. It is "ermitejob_" followed by 43 base64url characters
110 // (32 random bytes, no padding). The job_id of the request must be the136 // (32 random bytes, no padding). The job_id of the request must be the
111 // one of the token.137 // one of the token.
@@ -120,8 +146,8 @@ enum CancelReason {
120 //146 //
121 // The end of a job. A job ends when its conclusion is set, by CompleteJob or147 // The end of a job. A job ends when its conclusion is set, by CompleteJob or
122 // by the server (cancellation not honoured, lost runner, log limit, queue148 // by the server (cancellation not honoured, lost runner, log limit, queue
123-// timeout). From then on UpdateJob, AppendLog, Heartbeat and WatchJob answer149+// timeout). From then on UpdateJob, AppendLog, Heartbeat, WatchJob,
124-// failed_precondition with a JobEnded error detail (a JobEnded message in the150+// ResolveActions and UploadSummary answer failed_precondition with a JobEnded error detail (a JobEnded message in the
125 // Connect error details) that gives the conclusion; the runner stops the job151 // Connect error details) that gives the conclusion; the runner stops the job
126 // and sends nothing more. The job token is still recognised for 24 hours after152 // and sends nothing more. The job token is still recognised for 24 hours after
127 // the end, so that these calls can say so and so that CompleteJob, the only153 // the end, so that these calls can say so and so that CompleteJob, the only
@@ -132,14 +158,22 @@ enum CancelReason {
132 // Secrets and trust. Runner tokens and job tokens are secrets: the server158 // Secrets and trust. Runner tokens and job tokens are secrets: the server
133 // never logs them and clients must not log them. The job token stays in the159 // never logs them and clients must not log them. The job token stays in the
134 // runner host process; it is never given to the sandbox that runs the job's160 // runner host process; it is never given to the sandbox that runs the job's
135-// code. A runner receives the jobs of every repository, with their workflow161+// code. The job's repository token (Job.github_token) is another secret: it is
162+// the one the sandbox does get, and it only reads the repository of the run.
163+// A runner receives the jobs of every repository, with their workflow
136 // files, contexts and (from CI-2) their code, and from CI-3 their secrets: the164 // files, contexts and (from CI-2) their code, and from CI-3 their secrets: the
137 // runner:register scope therefore effectively gives read access to the code165 // runner:register scope therefore effectively gives read access to the code
138 // and the secrets of every repository, private ones included. Give it only to166 // and the secrets of every repository, private ones included. Give it only to
139 // runners you operate.167 // runners you operate.
140 //168 //
141 // Servers that implement this service list "ci.runners" in169 // Servers that implement this service list "ci.runners" in
142-// GetVersionResponse.features.170+// GetVersionResponse.features. Those that implement ResolveActions and
171+// Job.github_token also list "ci.actions", those that accept annotations
172+// (UpdateJobRequest.annotations, CompleteJobRequest.annotations) list
173+// "ci.annotations", and those that implement UploadSummary list
174+// "ci.summaries". A server without a feature ignores the fields of that
175+// feature (protobuf drops unknown fields) and answers unimplemented to its
176+// RPCs; a runner that needs one checks GetVersion first.
143 service RunnerService {177 service RunnerService {
144 // RegisterRunner registers a runner and returns its runner token, which is178 // RegisterRunner registers a runner and returns its runner token, which is
145 // shown only in this response; the runner keeps it. The caller needs the179 // shown only in this response; the runner keeps it. The caller needs the
@@ -191,10 +225,21 @@ service RunnerService {
191 // identical call changes nothing, so a runner may retry after a network225 // identical call changes nothing, so a runner may retry after a network
192 // error. To end the job use CompleteJob.226 // error. To end the job use CompleteJob.
193 //227 //
194- // Fails with invalid_argument if a rule is broken, with failed_precondition228+ // Annotations are applied with the steps, in the same atomic step: for each
195- // if a step goes back (a COMPLETED step cannot change, a step cannot go from229+ // step_number present in annotations, the annotations of that step stored
196- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail230+ // so far are replaced by the ones of the request, so a retry never
197- // if the job has ended.231+ // duplicates them. A step number absent from the request keeps its
232+ // annotations. The step of an annotation need not be in the steps of the
233+ // same call, and may already be COMPLETED: its annotations can still be
234+ // replaced (the rule that a COMPLETED step cannot change applies to
235+ // StepUpdate, not to annotations), until the job ends. A runner sends one
236+ // UpdateJob (or CompleteJob) at a time for a job, never concurrent calls,
237+ // so replacements apply in the order of the calls.
238+ //
239+ // Fails with invalid_argument if a rule is broken (including the annotation
240+ // limits), with failed_precondition if a step goes back (a COMPLETED step
241+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
242+ // failed_precondition and a JobEnded detail if the job has ended.
198 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);243 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);
199 // AppendLog appends lines to the log of a job. Needs the job token.244 // AppendLog appends lines to the log of a job. Needs the job token.
200 //245 //
@@ -299,9 +344,57 @@ service RunnerService {
299 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when344 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
300 // they never started and the job did not end by cancellation).345 // they never started and the job did not end by cancellation).
301 //346 //
302- // Fails with invalid_argument if a rule is broken (including the output347+ // Annotations are applied as in UpdateJob (replacement per step number, also
303- // limits) and failed_precondition if a step goes back, as in UpdateJob.348+ // for COMPLETED steps and steps not in steps), together with the conclusion.
349+ // Summaries are not part of this call: a runner sends them with
350+ // UploadSummary before it.
351+ //
352+ // Fails with invalid_argument if a rule is broken (including the output and
353+ // annotation limits) and failed_precondition if a step goes back, as in
354+ // UpdateJob.
304 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);355 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);
356+ // ResolveActions turns the "uses" of workflow and action steps into what the
357+ // runner needs to download the actions, as GitHub's action download info
358+ // does. Needs the job token; the job_id must be the one of the token. It
359+ // may be called as often as needed while the job runs (the runner calls it
360+ // once per level of composite actions, see the runner's depth limit of 9).
361+ // The runner then downloads each archive itself, from the sandbox, with the
362+ // token of the ResolvedAction when there is one.
363+ //
364+ // The response has one ResolvedAction per ActionRef, in the same order. A
365+ // reference that cannot be resolved (unknown repository, tag or branch, a
366+ // repository without access, a "uses" that GitHub itself would reject) does
367+ // not fail the call: its ResolvedAction has only ref and error, where error
368+ // is the message GitHub gives for the same failure, which the runner prints
369+ // as is. Only a failure of the call itself (credential, ended job, bad
370+ // request, server error) is an RPC error; the runner then fails the job.
371+ //
372+ // Resolution is stable for a run attempt: the same ref resolves to the same
373+ // sha (ResolvedAction.resolved_sha) for every job and every call of that
374+ // attempt. A re-run attempt resolves again. Tokens are not shared: each
375+ // job gets its own (ResolvedAction.token).
376+ //
377+ // Fails with unauthenticated or permission_denied as the other job RPCs,
378+ // with failed_precondition and a JobEnded detail if the job has ended, and
379+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
380+ // local action ("./path") or a Docker image ("docker://"), which the runner
381+ // handles without the server.
382+ rpc ResolveActions(ResolveActionsRequest) returns (ResolveActionsResponse);
383+ // UploadSummary stores the job summary of one step: the Markdown that the
384+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
385+ // The runner masks it before sending it, and sends it after the step ended
386+ // and before CompleteJob.
387+ //
388+ // It is idempotent: the summary of a step is replaced by each call, so a
389+ // retry changes nothing, and an empty markdown removes the summary of the
390+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8. The
391+ // server reads requests of up to 1 MiB plus the envelope (job id, step
392+ // number, framing), so a summary of exactly 1 MiB is accepted; clients set
393+ // their own message size limit above that.
394+ //
395+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
396+ // and with failed_precondition and a JobEnded detail if the job has ended.
397+ rpc UploadSummary(UploadSummaryRequest) returns (UploadSummaryResponse);
305 }398 }
306 399
307 // RegisterRunnerRequest describes the runner to register.400 // RegisterRunnerRequest describes the runner to register.
@@ -437,6 +530,18 @@ message Job {
437 // Ref is the full ref name that triggered the run, for example530 // Ref is the full ref name that triggered the run, for example
438 // "refs/heads/main" or "refs/tags/v1.0.0".531 // "refs/heads/main" or "refs/tags/v1.0.0".
439 string ref = 14;532 string ref = 14;
533+ // GithubToken is the job repository token, the "github.token" and
534+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
535+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
536+ // the job: the runner gives it to the sandbox (actions/checkout clones with
537+ // it). It can only read the repository of the run (read-only, whatever
538+ // "permissions:" says), and is valid from the assignment until the job ends
539+ // (it is revoked then, on cancellation and when the job is lost). It is a
540+ // secret: the runner registers it in its masker before anything runs, and
541+ // neither the runner nor the server logs it. It is shown only in this
542+ // response, or in a repeat of the same poll_id; a new assignment of the same
543+ // job has a new one. Empty from servers without the feature "ci.actions".
544+ string github_token = 15;
440 }545 }
441 546
442 // UpdateJobRequest reports the steps of a running job.547 // UpdateJobRequest reports the steps of a running job.
@@ -449,6 +554,13 @@ message UpdateJobRequest {
449 // implicit "Set up job" is 1, the steps of the workflow follow in order, and554 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
450 // the implicit "Complete job" is last.555 // the implicit "Complete job" is last.
451 repeated StepUpdate steps = 2;556 repeated StepUpdate steps = 2;
557+ // Annotations are the annotations of the steps that the call names: for
558+ // each step_number present, all the annotations of that step known so far,
559+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
560+ // and per step, and each one within the limits of Annotation; otherwise the
561+ // whole call is invalid_argument. The server ignores them without the
562+ // feature "ci.annotations".
563+ repeated Annotation annotations = 3;
452 }564 }
453 565
454 // StepUpdate is the state of one step as the runner knows it.566 // StepUpdate is the state of one step as the runner knows it.
@@ -472,6 +584,14 @@ message StepUpdate {
472 // CompletedAt is when the step ended, by the clock of the runner. Required584 // CompletedAt is when the step ended, by the clock of the runner. Required
473 // when state is COMPLETED.585 // when state is COMPLETED.
474 google.protobuf.Timestamp completed_at = 6;586 google.protobuf.Timestamp completed_at = 6;
587+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
588+ // "steps.<id>.outcome", whereas conclusion is the result after it
589+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
590+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
591+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
592+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
593+ // (a runner that does not know the field).
594+ CiConclusion outcome = 7;
475 }595 }
476 596
477 // UpdateJobResponse is empty.597 // UpdateJobResponse is empty.
@@ -504,6 +624,11 @@ message CompleteJobRequest {
504 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,624 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
505 // applied in the same atomic step as the conclusion.625 // applied in the same atomic step as the conclusion.
506 repeated StepUpdate steps = 5;626 repeated StepUpdate steps = 5;
627+ // Annotations are those of the steps that changed since the last call, with
628+ // the rules of UpdateJobRequest.annotations (all the annotations of each
629+ // step named). The server ignores them without the feature
630+ // "ci.annotations".
631+ repeated Annotation annotations = 6;
507 }632 }
508 633
509 // CompleteJobResponse is the stored result of a job.634 // CompleteJobResponse is the stored result of a job.
@@ -620,3 +745,117 @@ message CancelRequest {
620 // server.745 // server.
621 google.protobuf.Timestamp requested_at = 3;746 google.protobuf.Timestamp requested_at = 3;
622 }747 }
748+
749+// Annotation is a message attached to a step, and optionally to a place in a
750+// file of the repository, like an annotation of a GitHub check run. The runner
751+// produces them from the workflow commands ::notice, ::warning and ::error and
752+// from problem matchers, after masking.
753+//
754+// Limits, checked by the server: at most 10 annotations of each level per step
755+// (the runner sends no more: the ones beyond only reach the log, as with
756+// GitHub). A call that breaks a limit below is rejected whole with
757+// invalid_argument. Lengths count characters (Unicode code points), not bytes.
758+message Annotation {
759+ // Level is the severity. Required.
760+ AnnotationLevel level = 1;
761+ // Title is the optional title, at most 255 characters. Empty when not given.
762+ string title = 2;
763+ // Message is the text. Required, not empty, at most 4,096 characters; a
764+ // longer one is invalid_argument. The runner never sends a longer one: like
765+ // GitHub, it only logs such an annotation.
766+ string message = 3;
767+ // File is the path the annotation is about, relative to the repository when
768+ // the runner can tell, else as given. At most 1,024 characters. Empty when
769+ // the annotation is not about a file.
770+ string file = 4;
771+ // StartLine is the first line, counted from 1. 0 when not given.
772+ int32 start_line = 5;
773+ // EndLine is the last line, counted from 1, not before start_line. 0 when
774+ // not given.
775+ int32 end_line = 6;
776+ // StartColumn is the first column, counted from 1. 0 when not given.
777+ int32 start_column = 7;
778+ // EndColumn is the last column, counted from 1. 0 when not given.
779+ int32 end_column = 8;
780+ // StepNumber is the number of the step that produced it (see
781+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
782+ // composite action belongs to the step of the workflow that uses the action.
783+ int32 step_number = 9;
784+}
785+
786+// ActionRef is an action to resolve.
787+message ActionRef {
788+ // Uses is the value of "uses" as written, after expression evaluation, for
789+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
790+ string uses = 1;
791+}
792+
793+// ResolveActionsRequest lists the actions to resolve.
794+message ResolveActionsRequest {
795+ // JobId is the Job.job_id. It must be the job of the token.
796+ string job_id = 1;
797+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
798+ // answered one by one.
799+ repeated ActionRef refs = 2;
800+}
801+
802+// ResolveActionsResponse holds the resolution of each action.
803+message ResolveActionsResponse {
804+ // Actions has one entry per ActionRef of the request, in the same order.
805+ repeated ResolvedAction actions = 1;
806+}
807+
808+// ResolvedAction is where to download one action, or why it cannot be.
809+message ResolvedAction {
810+ // Ref is the ActionRef.uses of the request, unchanged.
811+ string ref = 1;
812+ // NameWithOwner is the repository of the action, "owner/repo", with the
813+ // case of the repository as the source gives it. Empty when error is set.
814+ string name_with_owner = 2;
815+ // Path is the sub-path of the action inside the repository, a clean
816+ // relative path: "path/to/action" for "owner/repo/path/to/action@ref", with
817+ // "/" separators, no leading or trailing slash, no empty, "." or ".."
818+ // element, never absolute. Empty for an action at the root of the
819+ // repository.
820+ string path = 3;
821+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
822+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
823+ // to, not the tag object). Stable for a run attempt: every job and every
824+ // call of the attempt gets the same value for the same ref. Empty when error
825+ // is set.
826+ string resolved_sha = 4;
827+ // TarballUrl is where to download the archive of the repository at
828+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
829+ // runner downloads it from the sandbox. Empty when error is set.
830+ string tarball_url = 5;
831+ // Token authenticates the download: the runner sends it as "Authorization:
832+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
833+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
834+ // valid until the job ends, so a job can use an action of another private
835+ // repository of the server that its own repository token cannot read. It is
836+ // issued per job and never shared across jobs (two jobs resolving the same
837+ // action get different tokens). It is a secret: the runner masks it, and neither the runner nor the server logs
838+ // it.
839+ string token = 6;
840+ // Source is where the action was found. UNSPECIFIED when error is set.
841+ ActionSource source = 7;
842+ // Error is why the reference could not be resolved, in the words of GitHub
843+ // for the same failure. Empty when the action was resolved, in which case
844+ // the other fields describe it.
845+ string error = 8;
846+}
847+
848+// UploadSummaryRequest carries the job summary of one step.
849+message UploadSummaryRequest {
850+ // JobId is the Job.job_id. It must be the job of the token.
851+ string job_id = 1;
852+ // StepNumber is the number of the step that wrote the summary (see
853+ // StepUpdate.number), from 1 to 1,000.
854+ int32 step_number = 2;
855+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
856+ // bytes). Empty removes the summary of the step.
857+ string markdown = 3;
858+}
859+
860+// UploadSummaryResponse is empty.
861+message UploadSummaryResponse {}
M proto/ermite/server.proto +5 -1
@@ -35,7 +35,11 @@ message GetVersionResponse {
3535 // identifiers are "ci.runs" (RunService runs, jobs, logs, checks, and the
3636 // run_updated and job_updated events), "ci.runs.filters" (ListRuns honours
3737 // its filters) and "ci.runners" (RunnerService, and RunService.ListRunners
38- // and RemoveRunner).
38+ // and RemoveRunner). The CI execution identifiers are "ci.actions"
39+ // (RunnerService.ResolveActions and Job.github_token), "ci.annotations"
40+ // (annotations in UpdateJob and CompleteJob, and RunService.ListAnnotations)
41+ // and "ci.summaries" (RunnerService.UploadSummary and
42+ // RunService.GetStepSummaries).
3943 repeated string features = 2;
4044 }
4145
@@ -35,7 +35,11 @@ message GetVersionResponse {
35 // identifiers are "ci.runs" (RunService runs, jobs, logs, checks, and the35 // identifiers are "ci.runs" (RunService runs, jobs, logs, checks, and the
36 // run_updated and job_updated events), "ci.runs.filters" (ListRuns honours36 // run_updated and job_updated events), "ci.runs.filters" (ListRuns honours
37 // its filters) and "ci.runners" (RunnerService, and RunService.ListRunners37 // its filters) and "ci.runners" (RunnerService, and RunService.ListRunners
38- // and RemoveRunner).38+ // and RemoveRunner). The CI execution identifiers are "ci.actions"
39+ // (RunnerService.ResolveActions and Job.github_token), "ci.annotations"
40+ // (annotations in UpdateJob and CompleteJob, and RunService.ListAnnotations)
41+ // and "ci.summaries" (RunnerService.UploadSummary and
42+ // RunService.GetStepSummaries).
39 repeated string features = 2;43 repeated string features = 2;
40 }44 }
41 45

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