detached 1541ed7

feat(ci): add actions, annotations and summaries to the CI protocol

Job.github_token, RunnerService.ResolveActions and UploadSummary, StepUpdate.outcome, Annotation on UpdateJob and CompleteJob, RunService.ListAnnotations and GetStepSummaries, Step.outcome, and the ci.actions, ci.annotations and ci.summaries features.
commit
1541ed78879d9a6ad1497253f775c91d0d81bfb6
author
brice · · 2026-10-13 09:12 UTC
parent
4db3b8b
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
10 files · +2054 -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 +93 -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,21 @@ 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. Needs the same access as GetRun. Returns at most
82+ // 1,000 annotations (truncated tells). A run without annotations gives an
83+ // empty list. Only servers with the feature "ci.annotations" implement it
84+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
85+ // the job does not exist, or if the job is not a job of the run.
86+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
87+ // GetStepSummaries returns the job summaries (the Markdown written to
88+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
89+ // number. Needs the same access as GetJob. Only servers with the feature
90+ // "ci.summaries" implement it (unimplemented otherwise). A job without
91+ // summaries gives an empty list. Fails with not_found if the job or the
92+ // attempt does not exist.
93+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
7394 // GetJobLog streams the lines of the log of a job, from a line number. The
7495 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
7596 // text each.
@@ -148,6 +169,18 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
148169 connect.WithSchema(runServiceMethods.ByName("GetJob")),
149170 connect.WithClientOptions(opts...),
150171 ),
172+ listAnnotations: connect.NewClient[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse](
173+ httpClient,
174+ baseURL+RunServiceListAnnotationsProcedure,
175+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
176+ connect.WithClientOptions(opts...),
177+ ),
178+ getStepSummaries: connect.NewClient[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse](
179+ httpClient,
180+ baseURL+RunServiceGetStepSummariesProcedure,
181+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
182+ connect.WithClientOptions(opts...),
183+ ),
151184 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](
152185 httpClient,
153186 baseURL+RunServiceGetJobLogProcedure,
@@ -189,15 +222,17 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
189222
190223 // runServiceClient implements RunServiceClient.
191224 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]
225+ listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]
226+ getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]
227+ getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]
228+ listAnnotations *connect.Client[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse]
229+ getStepSummaries *connect.Client[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse]
230+ getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]
231+ cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]
232+ rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]
233+ listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]
234+ listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]
235+ removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]
201236 }
202237
203238 // ListRuns calls ermite.RunService.ListRuns.
@@ -215,6 +250,16 @@ func (c *runServiceClient) GetJob(ctx context.Context, req *connect.Request[ermi
215250 return c.getJob.CallUnary(ctx, req)
216251 }
217252
253+// ListAnnotations calls ermite.RunService.ListAnnotations.
254+func (c *runServiceClient) ListAnnotations(ctx context.Context, req *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
255+ return c.listAnnotations.CallUnary(ctx, req)
256+}
257+
258+// GetStepSummaries calls ermite.RunService.GetStepSummaries.
259+func (c *runServiceClient) GetStepSummaries(ctx context.Context, req *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
260+ return c.getStepSummaries.CallUnary(ctx, req)
261+}
262+
218263 // GetJobLog calls ermite.RunService.GetJobLog.
219264 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {
220265 return c.getJobLog.CallServerStream(ctx, req)
@@ -260,6 +305,21 @@ type RunServiceHandler interface {
260305 // GetJob returns one job with its steps. Fails with not_found if the job
261306 // or the attempt does not exist.
262307 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
308+ // ListAnnotations lists the annotations of a run attempt, optionally of one
309+ // job, ordered by job (as in GetRun), step number, then the order in which
310+ // the step produced them. Needs the same access as GetRun. Returns at most
311+ // 1,000 annotations (truncated tells). A run without annotations gives an
312+ // empty list. Only servers with the feature "ci.annotations" implement it
313+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
314+ // the job does not exist, or if the job is not a job of the run.
315+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
316+ // GetStepSummaries returns the job summaries (the Markdown written to
317+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
318+ // number. Needs the same access as GetJob. Only servers with the feature
319+ // "ci.summaries" implement it (unimplemented otherwise). A job without
320+ // summaries gives an empty list. Fails with not_found if the job or the
321+ // attempt does not exist.
322+ GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error)
263323 // GetJobLog streams the lines of the log of a job, from a line number. The
264324 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
265325 // text each.
@@ -334,6 +394,18 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
334394 connect.WithSchema(runServiceMethods.ByName("GetJob")),
335395 connect.WithHandlerOptions(opts...),
336396 )
397+ runServiceListAnnotationsHandler := connect.NewUnaryHandler(
398+ RunServiceListAnnotationsProcedure,
399+ svc.ListAnnotations,
400+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
401+ connect.WithHandlerOptions(opts...),
402+ )
403+ runServiceGetStepSummariesHandler := connect.NewUnaryHandler(
404+ RunServiceGetStepSummariesProcedure,
405+ svc.GetStepSummaries,
406+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
407+ connect.WithHandlerOptions(opts...),
408+ )
337409 runServiceGetJobLogHandler := connect.NewServerStreamHandler(
338410 RunServiceGetJobLogProcedure,
339411 svc.GetJobLog,
@@ -378,6 +450,10 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
378450 runServiceGetRunHandler.ServeHTTP(w, r)
379451 case RunServiceGetJobProcedure:
380452 runServiceGetJobHandler.ServeHTTP(w, r)
453+ case RunServiceListAnnotationsProcedure:
454+ runServiceListAnnotationsHandler.ServeHTTP(w, r)
455+ case RunServiceGetStepSummariesProcedure:
456+ runServiceGetStepSummariesHandler.ServeHTTP(w, r)
381457 case RunServiceGetJobLogProcedure:
382458 runServiceGetJobLogHandler.ServeHTTP(w, r)
383459 case RunServiceCancelRunProcedure:
@@ -411,6 +487,14 @@ func (UnimplementedRunServiceHandler) GetJob(context.Context, *connect.Request[e
411487 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))
412488 }
413489
490+func (UnimplementedRunServiceHandler) ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
491+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.ListAnnotations is not implemented"))
492+}
493+
494+func (UnimplementedRunServiceHandler) GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
495+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetStepSummaries is not implemented"))
496+}
497+
414498 func (UnimplementedRunServiceHandler) GetJobLog(context.Context, *connect.Request[ermite.GetJobLogRequest], *connect.ServerStream[ermite.GetJobLogResponse]) error {
415499 return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJobLog is not implemented"))
416500 }
@@ -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,21 @@ 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. Needs the same access as GetRun. Returns at most
82+ // 1,000 annotations (truncated tells). A run without annotations gives an
83+ // empty list. Only servers with the feature "ci.annotations" implement it
84+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
85+ // the job does not exist, or if the job is not a job of the run.
86+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
87+ // GetStepSummaries returns the job summaries (the Markdown written to
88+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
89+ // number. Needs the same access as GetJob. Only servers with the feature
90+ // "ci.summaries" implement it (unimplemented otherwise). A job without
91+ // summaries gives an empty list. Fails with not_found if the job or the
92+ // attempt does not exist.
93+ 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. The94 // 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 of95 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
75 // text each.96 // text each.
@@ -148,6 +169,18 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
148 connect.WithSchema(runServiceMethods.ByName("GetJob")),169 connect.WithSchema(runServiceMethods.ByName("GetJob")),
149 connect.WithClientOptions(opts...),170 connect.WithClientOptions(opts...),
150 ),171 ),
172+ listAnnotations: connect.NewClient[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse](
173+ httpClient,
174+ baseURL+RunServiceListAnnotationsProcedure,
175+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
176+ connect.WithClientOptions(opts...),
177+ ),
178+ getStepSummaries: connect.NewClient[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse](
179+ httpClient,
180+ baseURL+RunServiceGetStepSummariesProcedure,
181+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
182+ connect.WithClientOptions(opts...),
183+ ),
151 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](184 getJobLog: connect.NewClient[ermite.GetJobLogRequest, ermite.GetJobLogResponse](
152 httpClient,185 httpClient,
153 baseURL+RunServiceGetJobLogProcedure,186 baseURL+RunServiceGetJobLogProcedure,
@@ -189,15 +222,17 @@ func NewRunServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...
189 222
190 // runServiceClient implements RunServiceClient.223 // runServiceClient implements RunServiceClient.
191 type runServiceClient struct {224 type runServiceClient struct {
192- listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]225+ listRuns *connect.Client[ermite.ListRunsRequest, ermite.ListRunsResponse]
193- getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]226+ getRun *connect.Client[ermite.GetRunRequest, ermite.GetRunResponse]
194- getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]227+ getJob *connect.Client[ermite.GetJobRequest, ermite.GetJobResponse]
195- getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]228+ listAnnotations *connect.Client[ermite.ListAnnotationsRequest, ermite.ListAnnotationsResponse]
196- cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]229+ getStepSummaries *connect.Client[ermite.GetStepSummariesRequest, ermite.GetStepSummariesResponse]
197- rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]230+ getJobLog *connect.Client[ermite.GetJobLogRequest, ermite.GetJobLogResponse]
198- listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]231+ cancelRun *connect.Client[ermite.CancelRunRequest, ermite.CancelRunResponse]
199- listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]232+ rerunRun *connect.Client[ermite.RerunRunRequest, ermite.RerunRunResponse]
200- removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]233+ listChecks *connect.Client[ermite.ListChecksRequest, ermite.ListChecksResponse]
234+ listRunners *connect.Client[ermite.ListRunnersRequest, ermite.ListRunnersResponse]
235+ removeRunner *connect.Client[ermite.RemoveRunnerRequest, ermite.RemoveRunnerResponse]
201 }236 }
202 237
203 // ListRuns calls ermite.RunService.ListRuns.238 // ListRuns calls ermite.RunService.ListRuns.
@@ -215,6 +250,16 @@ func (c *runServiceClient) GetJob(ctx context.Context, req *connect.Request[ermi
215 return c.getJob.CallUnary(ctx, req)250 return c.getJob.CallUnary(ctx, req)
216 }251 }
217 252
253+// ListAnnotations calls ermite.RunService.ListAnnotations.
254+func (c *runServiceClient) ListAnnotations(ctx context.Context, req *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
255+ return c.listAnnotations.CallUnary(ctx, req)
256+}
257+
258+// GetStepSummaries calls ermite.RunService.GetStepSummaries.
259+func (c *runServiceClient) GetStepSummaries(ctx context.Context, req *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
260+ return c.getStepSummaries.CallUnary(ctx, req)
261+}
262+
218 // GetJobLog calls ermite.RunService.GetJobLog.263 // GetJobLog calls ermite.RunService.GetJobLog.
219 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {264 func (c *runServiceClient) GetJobLog(ctx context.Context, req *connect.Request[ermite.GetJobLogRequest]) (*connect.ServerStreamForClient[ermite.GetJobLogResponse], error) {
220 return c.getJobLog.CallServerStream(ctx, req)265 return c.getJobLog.CallServerStream(ctx, req)
@@ -260,6 +305,21 @@ type RunServiceHandler interface {
260 // GetJob returns one job with its steps. Fails with not_found if the job305 // GetJob returns one job with its steps. Fails with not_found if the job
261 // or the attempt does not exist.306 // or the attempt does not exist.
262 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)307 GetJob(context.Context, *connect.Request[ermite.GetJobRequest]) (*connect.Response[ermite.GetJobResponse], error)
308+ // ListAnnotations lists the annotations of a run attempt, optionally of one
309+ // job, ordered by job (as in GetRun), step number, then the order in which
310+ // the step produced them. Needs the same access as GetRun. Returns at most
311+ // 1,000 annotations (truncated tells). A run without annotations gives an
312+ // empty list. Only servers with the feature "ci.annotations" implement it
313+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
314+ // the job does not exist, or if the job is not a job of the run.
315+ ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error)
316+ // GetStepSummaries returns the job summaries (the Markdown written to
317+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
318+ // number. Needs the same access as GetJob. Only servers with the feature
319+ // "ci.summaries" implement it (unimplemented otherwise). A job without
320+ // summaries gives an empty list. Fails with not_found if the job or the
321+ // attempt does not exist.
322+ 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. The323 // 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 of324 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
265 // text each.325 // text each.
@@ -334,6 +394,18 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
334 connect.WithSchema(runServiceMethods.ByName("GetJob")),394 connect.WithSchema(runServiceMethods.ByName("GetJob")),
335 connect.WithHandlerOptions(opts...),395 connect.WithHandlerOptions(opts...),
336 )396 )
397+ runServiceListAnnotationsHandler := connect.NewUnaryHandler(
398+ RunServiceListAnnotationsProcedure,
399+ svc.ListAnnotations,
400+ connect.WithSchema(runServiceMethods.ByName("ListAnnotations")),
401+ connect.WithHandlerOptions(opts...),
402+ )
403+ runServiceGetStepSummariesHandler := connect.NewUnaryHandler(
404+ RunServiceGetStepSummariesProcedure,
405+ svc.GetStepSummaries,
406+ connect.WithSchema(runServiceMethods.ByName("GetStepSummaries")),
407+ connect.WithHandlerOptions(opts...),
408+ )
337 runServiceGetJobLogHandler := connect.NewServerStreamHandler(409 runServiceGetJobLogHandler := connect.NewServerStreamHandler(
338 RunServiceGetJobLogProcedure,410 RunServiceGetJobLogProcedure,
339 svc.GetJobLog,411 svc.GetJobLog,
@@ -378,6 +450,10 @@ func NewRunServiceHandler(svc RunServiceHandler, opts ...connect.HandlerOption)
378 runServiceGetRunHandler.ServeHTTP(w, r)450 runServiceGetRunHandler.ServeHTTP(w, r)
379 case RunServiceGetJobProcedure:451 case RunServiceGetJobProcedure:
380 runServiceGetJobHandler.ServeHTTP(w, r)452 runServiceGetJobHandler.ServeHTTP(w, r)
453+ case RunServiceListAnnotationsProcedure:
454+ runServiceListAnnotationsHandler.ServeHTTP(w, r)
455+ case RunServiceGetStepSummariesProcedure:
456+ runServiceGetStepSummariesHandler.ServeHTTP(w, r)
381 case RunServiceGetJobLogProcedure:457 case RunServiceGetJobLogProcedure:
382 runServiceGetJobLogHandler.ServeHTTP(w, r)458 runServiceGetJobLogHandler.ServeHTTP(w, r)
383 case RunServiceCancelRunProcedure:459 case RunServiceCancelRunProcedure:
@@ -411,6 +487,14 @@ func (UnimplementedRunServiceHandler) GetJob(context.Context, *connect.Request[e
411 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))487 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJob is not implemented"))
412 }488 }
413 489
490+func (UnimplementedRunServiceHandler) ListAnnotations(context.Context, *connect.Request[ermite.ListAnnotationsRequest]) (*connect.Response[ermite.ListAnnotationsResponse], error) {
491+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.ListAnnotations is not implemented"))
492+}
493+
494+func (UnimplementedRunServiceHandler) GetStepSummaries(context.Context, *connect.Request[ermite.GetStepSummariesRequest]) (*connect.Response[ermite.GetStepSummariesResponse], error) {
495+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetStepSummaries is not implemented"))
496+}
497+
414 func (UnimplementedRunServiceHandler) GetJobLog(context.Context, *connect.Request[ermite.GetJobLogRequest], *connect.ServerStream[ermite.GetJobLogResponse]) error {498 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"))499 return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunService.GetJobLog is not implemented"))
416 }500 }
M gen/ermite/ermiteconnect/runner.connect.go +166 -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,16 @@ 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.
119+ //
120+ // Fails with invalid_argument if a rule is broken (including the annotation
121+ // limits), with failed_precondition if a step goes back (a COMPLETED step
122+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
123+ // failed_precondition and a JobEnded detail if the job has ended.
112124 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
113125 // AppendLog appends lines to the log of a job. Needs the job token.
114126 //
@@ -213,9 +225,53 @@ type RunnerServiceClient interface {
213225 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
214226 // they never started and the job did not end by cancellation).
215227 //
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.
228+ // Annotations are applied as in UpdateJob, together with the conclusion.
229+ // Summaries are not part of this call: a runner sends them with
230+ // UploadSummary before it.
231+ //
232+ // Fails with invalid_argument if a rule is broken (including the output and
233+ // annotation limits) and failed_precondition if a step goes back, as in
234+ // UpdateJob.
218235 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
236+ // ResolveActions turns the "uses" of workflow and action steps into what the
237+ // runner needs to download the actions, as GitHub's action download info
238+ // does. Needs the job token; the job_id must be the one of the token. It
239+ // may be called as often as needed while the job runs (the runner calls it
240+ // once per level of composite actions, see the runner's depth limit of 9).
241+ // The runner then downloads each archive itself, from the sandbox, with the
242+ // token of the ResolvedAction when there is one.
243+ //
244+ // The response has one ResolvedAction per ActionRef, in the same order. A
245+ // reference that cannot be resolved (unknown repository, tag or branch, a
246+ // repository without access, a "uses" that GitHub itself would reject) does
247+ // not fail the call: its ResolvedAction has only ref and error, where error
248+ // is the message GitHub gives for the same failure, which the runner prints
249+ // as is. Only a failure of the call itself (credential, ended job, bad
250+ // request, server error) is an RPC error; the runner then fails the job.
251+ //
252+ // Resolution is stable for a run: the same ref resolves to the same sha for
253+ // every job and every call of one attempt of the run. A re-run attempt
254+ // resolves again.
255+ //
256+ // Fails with unauthenticated or permission_denied as the other job RPCs,
257+ // with failed_precondition and a JobEnded detail if the job has ended, and
258+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
259+ // local action ("./path") or a Docker image ("docker://"), which the runner
260+ // handles without the server.
261+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
262+ // UploadSummary stores the job summary of one step: the Markdown that the
263+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
264+ // The runner masks it before sending it, and sends it after the step ended
265+ // and before CompleteJob.
266+ //
267+ // It is idempotent: the summary of a step is replaced by each call, so a
268+ // retry changes nothing, and an empty markdown removes the summary of the
269+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
270+ // clients set a message size limit above it.
271+ //
272+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
273+ // and with failed_precondition and a JobEnded detail if the job has ended.
274+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
219275 }
220276
221277 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it
@@ -271,6 +327,18 @@ func NewRunnerServiceClient(httpClient connect.HTTPClient, baseURL string, opts
271327 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
272328 connect.WithClientOptions(opts...),
273329 ),
330+ resolveActions: connect.NewClient[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse](
331+ httpClient,
332+ baseURL+RunnerServiceResolveActionsProcedure,
333+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
334+ connect.WithClientOptions(opts...),
335+ ),
336+ uploadSummary: connect.NewClient[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse](
337+ httpClient,
338+ baseURL+RunnerServiceUploadSummaryProcedure,
339+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
340+ connect.WithClientOptions(opts...),
341+ ),
274342 }
275343 }
276344
@@ -283,6 +351,8 @@ type runnerServiceClient struct {
283351 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]
284352 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]
285353 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]
354+ resolveActions *connect.Client[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse]
355+ uploadSummary *connect.Client[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse]
286356 }
287357
288358 // RegisterRunner calls ermite.RunnerService.RegisterRunner.
@@ -320,6 +390,16 @@ func (c *runnerServiceClient) CompleteJob(ctx context.Context, req *connect.Requ
320390 return c.completeJob.CallUnary(ctx, req)
321391 }
322392
393+// ResolveActions calls ermite.RunnerService.ResolveActions.
394+func (c *runnerServiceClient) ResolveActions(ctx context.Context, req *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
395+ return c.resolveActions.CallUnary(ctx, req)
396+}
397+
398+// UploadSummary calls ermite.RunnerService.UploadSummary.
399+func (c *runnerServiceClient) UploadSummary(ctx context.Context, req *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
400+ return c.uploadSummary.CallUnary(ctx, req)
401+}
402+
323403 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.
324404 type RunnerServiceHandler interface {
325405 // RegisterRunner registers a runner and returns its runner token, which is
@@ -372,10 +452,16 @@ type RunnerServiceHandler interface {
372452 // identical call changes nothing, so a runner may retry after a network
373453 // error. To end the job use CompleteJob.
374454 //
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.
455+ // Annotations are applied with the steps, in the same atomic step: for each
456+ // step_number present in annotations, the annotations of that step stored
457+ // so far are replaced by the ones of the request, so a retry never
458+ // duplicates them. A step number absent from the request keeps its
459+ // annotations.
460+ //
461+ // Fails with invalid_argument if a rule is broken (including the annotation
462+ // limits), with failed_precondition if a step goes back (a COMPLETED step
463+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
464+ // failed_precondition and a JobEnded detail if the job has ended.
379465 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)
380466 // AppendLog appends lines to the log of a job. Needs the job token.
381467 //
@@ -480,9 +566,53 @@ type RunnerServiceHandler interface {
480566 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
481567 // they never started and the job did not end by cancellation).
482568 //
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.
569+ // Annotations are applied as in UpdateJob, together with the conclusion.
570+ // Summaries are not part of this call: a runner sends them with
571+ // UploadSummary before it.
572+ //
573+ // Fails with invalid_argument if a rule is broken (including the output and
574+ // annotation limits) and failed_precondition if a step goes back, as in
575+ // UpdateJob.
485576 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
577+ // ResolveActions turns the "uses" of workflow and action steps into what the
578+ // runner needs to download the actions, as GitHub's action download info
579+ // does. Needs the job token; the job_id must be the one of the token. It
580+ // may be called as often as needed while the job runs (the runner calls it
581+ // once per level of composite actions, see the runner's depth limit of 9).
582+ // The runner then downloads each archive itself, from the sandbox, with the
583+ // token of the ResolvedAction when there is one.
584+ //
585+ // The response has one ResolvedAction per ActionRef, in the same order. A
586+ // reference that cannot be resolved (unknown repository, tag or branch, a
587+ // repository without access, a "uses" that GitHub itself would reject) does
588+ // not fail the call: its ResolvedAction has only ref and error, where error
589+ // is the message GitHub gives for the same failure, which the runner prints
590+ // as is. Only a failure of the call itself (credential, ended job, bad
591+ // request, server error) is an RPC error; the runner then fails the job.
592+ //
593+ // Resolution is stable for a run: the same ref resolves to the same sha for
594+ // every job and every call of one attempt of the run. A re-run attempt
595+ // resolves again.
596+ //
597+ // Fails with unauthenticated or permission_denied as the other job RPCs,
598+ // with failed_precondition and a JobEnded detail if the job has ended, and
599+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
600+ // local action ("./path") or a Docker image ("docker://"), which the runner
601+ // handles without the server.
602+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
603+ // UploadSummary stores the job summary of one step: the Markdown that the
604+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
605+ // The runner masks it before sending it, and sends it after the step ended
606+ // and before CompleteJob.
607+ //
608+ // It is idempotent: the summary of a step is replaced by each call, so a
609+ // retry changes nothing, and an empty markdown removes the summary of the
610+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
611+ // clients set a message size limit above it.
612+ //
613+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
614+ // and with failed_precondition and a JobEnded detail if the job has ended.
615+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
486616 }
487617
488618 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the
@@ -534,6 +664,18 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
534664 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
535665 connect.WithHandlerOptions(opts...),
536666 )
667+ runnerServiceResolveActionsHandler := connect.NewUnaryHandler(
668+ RunnerServiceResolveActionsProcedure,
669+ svc.ResolveActions,
670+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
671+ connect.WithHandlerOptions(opts...),
672+ )
673+ runnerServiceUploadSummaryHandler := connect.NewUnaryHandler(
674+ RunnerServiceUploadSummaryProcedure,
675+ svc.UploadSummary,
676+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
677+ connect.WithHandlerOptions(opts...),
678+ )
537679 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
538680 switch r.URL.Path {
539681 case RunnerServiceRegisterRunnerProcedure:
@@ -550,6 +692,10 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
550692 runnerServiceWatchJobHandler.ServeHTTP(w, r)
551693 case RunnerServiceCompleteJobProcedure:
552694 runnerServiceCompleteJobHandler.ServeHTTP(w, r)
695+ case RunnerServiceResolveActionsProcedure:
696+ runnerServiceResolveActionsHandler.ServeHTTP(w, r)
697+ case RunnerServiceUploadSummaryProcedure:
698+ runnerServiceUploadSummaryHandler.ServeHTTP(w, r)
553699 default:
554700 http.NotFound(w, r)
555701 }
@@ -586,3 +732,11 @@ func (UnimplementedRunnerServiceHandler) WatchJob(context.Context, *connect.Requ
586732 func (UnimplementedRunnerServiceHandler) CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error) {
587733 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.CompleteJob is not implemented"))
588734 }
735+
736+func (UnimplementedRunnerServiceHandler) ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
737+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.ResolveActions is not implemented"))
738+}
739+
740+func (UnimplementedRunnerServiceHandler) UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
741+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.UploadSummary is not implemented"))
742+}
@@ -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,16 @@ 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.
119+ //
120+ // Fails with invalid_argument if a rule is broken (including the annotation
121+ // limits), with failed_precondition if a step goes back (a COMPLETED step
122+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
123+ // failed_precondition and a JobEnded detail if the job has ended.
112 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)124 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.125 // AppendLog appends lines to the log of a job. Needs the job token.
114 //126 //
@@ -213,9 +225,53 @@ type RunnerServiceClient interface {
213 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when225 // 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).226 // they never started and the job did not end by cancellation).
215 //227 //
216- // Fails with invalid_argument if a rule is broken (including the output228+ // Annotations are applied as in UpdateJob, together with the conclusion.
217- // limits) and failed_precondition if a step goes back, as in UpdateJob.229+ // Summaries are not part of this call: a runner sends them with
230+ // UploadSummary before it.
231+ //
232+ // Fails with invalid_argument if a rule is broken (including the output and
233+ // annotation limits) and failed_precondition if a step goes back, as in
234+ // UpdateJob.
218 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)235 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
236+ // ResolveActions turns the "uses" of workflow and action steps into what the
237+ // runner needs to download the actions, as GitHub's action download info
238+ // does. Needs the job token; the job_id must be the one of the token. It
239+ // may be called as often as needed while the job runs (the runner calls it
240+ // once per level of composite actions, see the runner's depth limit of 9).
241+ // The runner then downloads each archive itself, from the sandbox, with the
242+ // token of the ResolvedAction when there is one.
243+ //
244+ // The response has one ResolvedAction per ActionRef, in the same order. A
245+ // reference that cannot be resolved (unknown repository, tag or branch, a
246+ // repository without access, a "uses" that GitHub itself would reject) does
247+ // not fail the call: its ResolvedAction has only ref and error, where error
248+ // is the message GitHub gives for the same failure, which the runner prints
249+ // as is. Only a failure of the call itself (credential, ended job, bad
250+ // request, server error) is an RPC error; the runner then fails the job.
251+ //
252+ // Resolution is stable for a run: the same ref resolves to the same sha for
253+ // every job and every call of one attempt of the run. A re-run attempt
254+ // resolves again.
255+ //
256+ // Fails with unauthenticated or permission_denied as the other job RPCs,
257+ // with failed_precondition and a JobEnded detail if the job has ended, and
258+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
259+ // local action ("./path") or a Docker image ("docker://"), which the runner
260+ // handles without the server.
261+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
262+ // UploadSummary stores the job summary of one step: the Markdown that the
263+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
264+ // The runner masks it before sending it, and sends it after the step ended
265+ // and before CompleteJob.
266+ //
267+ // It is idempotent: the summary of a step is replaced by each call, so a
268+ // retry changes nothing, and an empty markdown removes the summary of the
269+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
270+ // clients set a message size limit above it.
271+ //
272+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
273+ // and with failed_precondition and a JobEnded detail if the job has ended.
274+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
219 }275 }
220 276
221 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it277 // NewRunnerServiceClient constructs a client for the ermite.RunnerService service. By default, it
@@ -271,6 +327,18 @@ func NewRunnerServiceClient(httpClient connect.HTTPClient, baseURL string, opts
271 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),327 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
272 connect.WithClientOptions(opts...),328 connect.WithClientOptions(opts...),
273 ),329 ),
330+ resolveActions: connect.NewClient[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse](
331+ httpClient,
332+ baseURL+RunnerServiceResolveActionsProcedure,
333+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
334+ connect.WithClientOptions(opts...),
335+ ),
336+ uploadSummary: connect.NewClient[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse](
337+ httpClient,
338+ baseURL+RunnerServiceUploadSummaryProcedure,
339+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
340+ connect.WithClientOptions(opts...),
341+ ),
274 }342 }
275 }343 }
276 344
@@ -283,6 +351,8 @@ type runnerServiceClient struct {
283 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]351 heartbeat *connect.Client[ermite.HeartbeatRequest, ermite.HeartbeatResponse]
284 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]352 watchJob *connect.Client[ermite.WatchJobRequest, ermite.WatchJobResponse]
285 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]353 completeJob *connect.Client[ermite.CompleteJobRequest, ermite.CompleteJobResponse]
354+ resolveActions *connect.Client[ermite.ResolveActionsRequest, ermite.ResolveActionsResponse]
355+ uploadSummary *connect.Client[ermite.UploadSummaryRequest, ermite.UploadSummaryResponse]
286 }356 }
287 357
288 // RegisterRunner calls ermite.RunnerService.RegisterRunner.358 // RegisterRunner calls ermite.RunnerService.RegisterRunner.
@@ -320,6 +390,16 @@ func (c *runnerServiceClient) CompleteJob(ctx context.Context, req *connect.Requ
320 return c.completeJob.CallUnary(ctx, req)390 return c.completeJob.CallUnary(ctx, req)
321 }391 }
322 392
393+// ResolveActions calls ermite.RunnerService.ResolveActions.
394+func (c *runnerServiceClient) ResolveActions(ctx context.Context, req *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
395+ return c.resolveActions.CallUnary(ctx, req)
396+}
397+
398+// UploadSummary calls ermite.RunnerService.UploadSummary.
399+func (c *runnerServiceClient) UploadSummary(ctx context.Context, req *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
400+ return c.uploadSummary.CallUnary(ctx, req)
401+}
402+
323 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.403 // RunnerServiceHandler is an implementation of the ermite.RunnerService service.
324 type RunnerServiceHandler interface {404 type RunnerServiceHandler interface {
325 // RegisterRunner registers a runner and returns its runner token, which is405 // RegisterRunner registers a runner and returns its runner token, which is
@@ -372,10 +452,16 @@ type RunnerServiceHandler interface {
372 // identical call changes nothing, so a runner may retry after a network452 // identical call changes nothing, so a runner may retry after a network
373 // error. To end the job use CompleteJob.453 // error. To end the job use CompleteJob.
374 //454 //
375- // Fails with invalid_argument if a rule is broken, with failed_precondition455+ // 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 from456+ // step_number present in annotations, the annotations of that step stored
377- // IN_PROGRESS to PENDING) and with failed_precondition and a JobEnded detail457+ // so far are replaced by the ones of the request, so a retry never
378- // if the job has ended.458+ // duplicates them. A step number absent from the request keeps its
459+ // annotations.
460+ //
461+ // Fails with invalid_argument if a rule is broken (including the annotation
462+ // limits), with failed_precondition if a step goes back (a COMPLETED step
463+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
464+ // failed_precondition and a JobEnded detail if the job has ended.
379 UpdateJob(context.Context, *connect.Request[ermite.UpdateJobRequest]) (*connect.Response[ermite.UpdateJobResponse], error)465 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.466 // AppendLog appends lines to the log of a job. Needs the job token.
381 //467 //
@@ -480,9 +566,53 @@ type RunnerServiceHandler interface {
480 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when566 // 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).567 // they never started and the job did not end by cancellation).
482 //568 //
483- // Fails with invalid_argument if a rule is broken (including the output569+ // Annotations are applied as in UpdateJob, together with the conclusion.
484- // limits) and failed_precondition if a step goes back, as in UpdateJob.570+ // Summaries are not part of this call: a runner sends them with
571+ // UploadSummary before it.
572+ //
573+ // Fails with invalid_argument if a rule is broken (including the output and
574+ // annotation limits) and failed_precondition if a step goes back, as in
575+ // UpdateJob.
485 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)576 CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error)
577+ // ResolveActions turns the "uses" of workflow and action steps into what the
578+ // runner needs to download the actions, as GitHub's action download info
579+ // does. Needs the job token; the job_id must be the one of the token. It
580+ // may be called as often as needed while the job runs (the runner calls it
581+ // once per level of composite actions, see the runner's depth limit of 9).
582+ // The runner then downloads each archive itself, from the sandbox, with the
583+ // token of the ResolvedAction when there is one.
584+ //
585+ // The response has one ResolvedAction per ActionRef, in the same order. A
586+ // reference that cannot be resolved (unknown repository, tag or branch, a
587+ // repository without access, a "uses" that GitHub itself would reject) does
588+ // not fail the call: its ResolvedAction has only ref and error, where error
589+ // is the message GitHub gives for the same failure, which the runner prints
590+ // as is. Only a failure of the call itself (credential, ended job, bad
591+ // request, server error) is an RPC error; the runner then fails the job.
592+ //
593+ // Resolution is stable for a run: the same ref resolves to the same sha for
594+ // every job and every call of one attempt of the run. A re-run attempt
595+ // resolves again.
596+ //
597+ // Fails with unauthenticated or permission_denied as the other job RPCs,
598+ // with failed_precondition and a JobEnded detail if the job has ended, and
599+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
600+ // local action ("./path") or a Docker image ("docker://"), which the runner
601+ // handles without the server.
602+ ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error)
603+ // UploadSummary stores the job summary of one step: the Markdown that the
604+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
605+ // The runner masks it before sending it, and sends it after the step ended
606+ // and before CompleteJob.
607+ //
608+ // It is idempotent: the summary of a step is replaced by each call, so a
609+ // retry changes nothing, and an empty markdown removes the summary of the
610+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
611+ // clients set a message size limit above it.
612+ //
613+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
614+ // and with failed_precondition and a JobEnded detail if the job has ended.
615+ UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error)
486 }616 }
487 617
488 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the618 // NewRunnerServiceHandler builds an HTTP handler from the service implementation. It returns the
@@ -534,6 +664,18 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
534 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),664 connect.WithSchema(runnerServiceMethods.ByName("CompleteJob")),
535 connect.WithHandlerOptions(opts...),665 connect.WithHandlerOptions(opts...),
536 )666 )
667+ runnerServiceResolveActionsHandler := connect.NewUnaryHandler(
668+ RunnerServiceResolveActionsProcedure,
669+ svc.ResolveActions,
670+ connect.WithSchema(runnerServiceMethods.ByName("ResolveActions")),
671+ connect.WithHandlerOptions(opts...),
672+ )
673+ runnerServiceUploadSummaryHandler := connect.NewUnaryHandler(
674+ RunnerServiceUploadSummaryProcedure,
675+ svc.UploadSummary,
676+ connect.WithSchema(runnerServiceMethods.ByName("UploadSummary")),
677+ connect.WithHandlerOptions(opts...),
678+ )
537 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {679 return "/ermite.RunnerService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
538 switch r.URL.Path {680 switch r.URL.Path {
539 case RunnerServiceRegisterRunnerProcedure:681 case RunnerServiceRegisterRunnerProcedure:
@@ -550,6 +692,10 @@ func NewRunnerServiceHandler(svc RunnerServiceHandler, opts ...connect.HandlerOp
550 runnerServiceWatchJobHandler.ServeHTTP(w, r)692 runnerServiceWatchJobHandler.ServeHTTP(w, r)
551 case RunnerServiceCompleteJobProcedure:693 case RunnerServiceCompleteJobProcedure:
552 runnerServiceCompleteJobHandler.ServeHTTP(w, r)694 runnerServiceCompleteJobHandler.ServeHTTP(w, r)
695+ case RunnerServiceResolveActionsProcedure:
696+ runnerServiceResolveActionsHandler.ServeHTTP(w, r)
697+ case RunnerServiceUploadSummaryProcedure:
698+ runnerServiceUploadSummaryHandler.ServeHTTP(w, r)
553 default:699 default:
554 http.NotFound(w, r)700 http.NotFound(w, r)
555 }701 }
@@ -586,3 +732,11 @@ func (UnimplementedRunnerServiceHandler) WatchJob(context.Context, *connect.Requ
586 func (UnimplementedRunnerServiceHandler) CompleteJob(context.Context, *connect.Request[ermite.CompleteJobRequest]) (*connect.Response[ermite.CompleteJobResponse], error) {732 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"))733 return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.CompleteJob is not implemented"))
588 }734 }
735+
736+func (UnimplementedRunnerServiceHandler) ResolveActions(context.Context, *connect.Request[ermite.ResolveActionsRequest]) (*connect.Response[ermite.ResolveActionsResponse], error) {
737+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.ResolveActions is not implemented"))
738+}
739+
740+func (UnimplementedRunnerServiceHandler) UploadSummary(context.Context, *connect.Request[ermite.UploadSummaryRequest]) (*connect.Response[ermite.UploadSummaryResponse], error) {
741+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.RunnerService.UploadSummary is not implemented"))
742+}
M gen/ermite/run.pb.go +537 -132 generated file: collapsed
M gen/ermite/runner.pb.go +829 -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,13 @@ 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; more is invalid_argument. The server ignores them without
984+ // the feature "ci.annotations".
985+ Annotations []*Annotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"`
847986 unknownFields protoimpl.UnknownFields
848987 sizeCache protoimpl.SizeCache
849988 }
@@ -892,6 +1031,13 @@ func (x *UpdateJobRequest) GetSteps() []*StepUpdate {
8921031 return nil
8931032 }
8941033
1034+func (x *UpdateJobRequest) GetAnnotations() []*Annotation {
1035+ if x != nil {
1036+ return x.Annotations
1037+ }
1038+ return nil
1039+}
1040+
8951041 // StepUpdate is the state of one step as the runner knows it.
8961042 type StepUpdate struct {
8971043 state protoimpl.MessageState `protogen:"open.v1"`
@@ -913,7 +1059,15 @@ type StepUpdate struct {
9131059 StartedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
9141060 // CompletedAt is when the step ended, by the clock of the runner. Required
9151061 // when state is COMPLETED.
916- CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1062+ CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1063+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
1064+ // "steps.<id>.outcome", whereas conclusion is the result after it
1065+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
1066+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
1067+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
1068+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
1069+ // (a runner that does not know the field).
1070+ Outcome CiConclusion `protobuf:"varint,7,opt,name=outcome,proto3,enum=ermite.CiConclusion" json:"outcome,omitempty"`
9171071 unknownFields protoimpl.UnknownFields
9181072 sizeCache protoimpl.SizeCache
9191073 }
@@ -990,6 +1144,13 @@ func (x *StepUpdate) GetCompletedAt() *timestamppb.Timestamp {
9901144 return nil
9911145 }
9921146
1147+func (x *StepUpdate) GetOutcome() CiConclusion {
1148+ if x != nil {
1149+ return x.Outcome
1150+ }
1151+ return CiConclusion_CI_CONCLUSION_UNSPECIFIED
1152+}
1153+
9931154 // UpdateJobResponse is empty.
9941155 type UpdateJobResponse struct {
9951156 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1054,7 +1215,12 @@ type CompleteJobRequest struct {
10541215 RunnerShutdown bool `protobuf:"varint,4,opt,name=runner_shutdown,json=runnerShutdown,proto3" json:"runner_shutdown,omitempty"`
10551216 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
10561217 // applied in the same atomic step as the conclusion.
1057- Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1218+ Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1219+ // Annotations are those of the steps that changed since the last call, with
1220+ // the rules of UpdateJobRequest.annotations (all the annotations of each
1221+ // step named). The server ignores them without the feature
1222+ // "ci.annotations".
1223+ Annotations []*Annotation `protobuf:"bytes,6,rep,name=annotations,proto3" json:"annotations,omitempty"`
10581224 unknownFields protoimpl.UnknownFields
10591225 sizeCache protoimpl.SizeCache
10601226 }
@@ -1124,6 +1290,13 @@ func (x *CompleteJobRequest) GetSteps() []*StepUpdate {
11241290 return nil
11251291 }
11261292
1293+func (x *CompleteJobRequest) GetAnnotations() []*Annotation {
1294+ if x != nil {
1295+ return x.Annotations
1296+ }
1297+ return nil
1298+}
1299+
11271300 // CompleteJobResponse is the stored result of a job.
11281301 type CompleteJobResponse struct {
11291302 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1788,6 +1961,512 @@ func (x *CancelRequest) GetRequestedAt() *timestamppb.Timestamp {
17881961 return nil
17891962 }
17901963
1964+// Annotation is a message attached to a step, and optionally to a place in a
1965+// file of the repository, like an annotation of a GitHub check run. The runner
1966+// produces them from the workflow commands ::notice, ::warning and ::error and
1967+// from problem matchers, after masking.
1968+//
1969+// The runner sends at most 10 annotations of each level per step (the ones
1970+// beyond only reach the log) and the server rejects more.
1971+type Annotation struct {
1972+ state protoimpl.MessageState `protogen:"open.v1"`
1973+ // Level is the severity. Required.
1974+ Level AnnotationLevel `protobuf:"varint,1,opt,name=level,proto3,enum=ermite.AnnotationLevel" json:"level,omitempty"`
1975+ // Title is the optional title. Empty when not given.
1976+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
1977+ // Message is the text, at most 4,096 characters (the runner cuts longer
1978+ // ones). Required, not empty.
1979+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
1980+ // File is the path the annotation is about, relative to the repository when
1981+ // the runner can tell, else as given. Empty when the annotation is not about
1982+ // a file.
1983+ File string `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
1984+ // StartLine is the first line, counted from 1. 0 when not given.
1985+ StartLine int32 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"`
1986+ // EndLine is the last line, counted from 1, not before start_line. 0 when
1987+ // not given.
1988+ EndLine int32 `protobuf:"varint,6,opt,name=end_line,json=endLine,proto3" json:"end_line,omitempty"`
1989+ // StartColumn is the first column, counted from 1. 0 when not given.
1990+ StartColumn int32 `protobuf:"varint,7,opt,name=start_column,json=startColumn,proto3" json:"start_column,omitempty"`
1991+ // EndColumn is the last column, counted from 1. 0 when not given.
1992+ EndColumn int32 `protobuf:"varint,8,opt,name=end_column,json=endColumn,proto3" json:"end_column,omitempty"`
1993+ // StepNumber is the number of the step that produced it (see
1994+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
1995+ // composite action belongs to the step of the workflow that uses the action.
1996+ StepNumber int32 `protobuf:"varint,9,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
1997+ unknownFields protoimpl.UnknownFields
1998+ sizeCache protoimpl.SizeCache
1999+}
2000+
2001+func (x *Annotation) Reset() {
2002+ *x = Annotation{}
2003+ mi := &file_ermite_runner_proto_msgTypes[20]
2004+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2005+ ms.StoreMessageInfo(mi)
2006+}
2007+
2008+func (x *Annotation) String() string {
2009+ return protoimpl.X.MessageStringOf(x)
2010+}
2011+
2012+func (*Annotation) ProtoMessage() {}
2013+
2014+func (x *Annotation) ProtoReflect() protoreflect.Message {
2015+ mi := &file_ermite_runner_proto_msgTypes[20]
2016+ if x != nil {
2017+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2018+ if ms.LoadMessageInfo() == nil {
2019+ ms.StoreMessageInfo(mi)
2020+ }
2021+ return ms
2022+ }
2023+ return mi.MessageOf(x)
2024+}
2025+
2026+// Deprecated: Use Annotation.ProtoReflect.Descriptor instead.
2027+func (*Annotation) Descriptor() ([]byte, []int) {
2028+ return file_ermite_runner_proto_rawDescGZIP(), []int{20}
2029+}
2030+
2031+func (x *Annotation) GetLevel() AnnotationLevel {
2032+ if x != nil {
2033+ return x.Level
2034+ }
2035+ return AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED
2036+}
2037+
2038+func (x *Annotation) GetTitle() string {
2039+ if x != nil {
2040+ return x.Title
2041+ }
2042+ return ""
2043+}
2044+
2045+func (x *Annotation) GetMessage() string {
2046+ if x != nil {
2047+ return x.Message
2048+ }
2049+ return ""
2050+}
2051+
2052+func (x *Annotation) GetFile() string {
2053+ if x != nil {
2054+ return x.File
2055+ }
2056+ return ""
2057+}
2058+
2059+func (x *Annotation) GetStartLine() int32 {
2060+ if x != nil {
2061+ return x.StartLine
2062+ }
2063+ return 0
2064+}
2065+
2066+func (x *Annotation) GetEndLine() int32 {
2067+ if x != nil {
2068+ return x.EndLine
2069+ }
2070+ return 0
2071+}
2072+
2073+func (x *Annotation) GetStartColumn() int32 {
2074+ if x != nil {
2075+ return x.StartColumn
2076+ }
2077+ return 0
2078+}
2079+
2080+func (x *Annotation) GetEndColumn() int32 {
2081+ if x != nil {
2082+ return x.EndColumn
2083+ }
2084+ return 0
2085+}
2086+
2087+func (x *Annotation) GetStepNumber() int32 {
2088+ if x != nil {
2089+ return x.StepNumber
2090+ }
2091+ return 0
2092+}
2093+
2094+// ActionRef is an action to resolve.
2095+type ActionRef struct {
2096+ state protoimpl.MessageState `protogen:"open.v1"`
2097+ // Uses is the value of "uses" as written, after expression evaluation, for
2098+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
2099+ Uses string `protobuf:"bytes,1,opt,name=uses,proto3" json:"uses,omitempty"`
2100+ unknownFields protoimpl.UnknownFields
2101+ sizeCache protoimpl.SizeCache
2102+}
2103+
2104+func (x *ActionRef) Reset() {
2105+ *x = ActionRef{}
2106+ mi := &file_ermite_runner_proto_msgTypes[21]
2107+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2108+ ms.StoreMessageInfo(mi)
2109+}
2110+
2111+func (x *ActionRef) String() string {
2112+ return protoimpl.X.MessageStringOf(x)
2113+}
2114+
2115+func (*ActionRef) ProtoMessage() {}
2116+
2117+func (x *ActionRef) ProtoReflect() protoreflect.Message {
2118+ mi := &file_ermite_runner_proto_msgTypes[21]
2119+ if x != nil {
2120+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2121+ if ms.LoadMessageInfo() == nil {
2122+ ms.StoreMessageInfo(mi)
2123+ }
2124+ return ms
2125+ }
2126+ return mi.MessageOf(x)
2127+}
2128+
2129+// Deprecated: Use ActionRef.ProtoReflect.Descriptor instead.
2130+func (*ActionRef) Descriptor() ([]byte, []int) {
2131+ return file_ermite_runner_proto_rawDescGZIP(), []int{21}
2132+}
2133+
2134+func (x *ActionRef) GetUses() string {
2135+ if x != nil {
2136+ return x.Uses
2137+ }
2138+ return ""
2139+}
2140+
2141+// ResolveActionsRequest lists the actions to resolve.
2142+type ResolveActionsRequest struct {
2143+ state protoimpl.MessageState `protogen:"open.v1"`
2144+ // JobId is the Job.job_id. It must be the job of the token.
2145+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2146+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
2147+ // answered one by one.
2148+ Refs []*ActionRef `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"`
2149+ unknownFields protoimpl.UnknownFields
2150+ sizeCache protoimpl.SizeCache
2151+}
2152+
2153+func (x *ResolveActionsRequest) Reset() {
2154+ *x = ResolveActionsRequest{}
2155+ mi := &file_ermite_runner_proto_msgTypes[22]
2156+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2157+ ms.StoreMessageInfo(mi)
2158+}
2159+
2160+func (x *ResolveActionsRequest) String() string {
2161+ return protoimpl.X.MessageStringOf(x)
2162+}
2163+
2164+func (*ResolveActionsRequest) ProtoMessage() {}
2165+
2166+func (x *ResolveActionsRequest) ProtoReflect() protoreflect.Message {
2167+ mi := &file_ermite_runner_proto_msgTypes[22]
2168+ if x != nil {
2169+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2170+ if ms.LoadMessageInfo() == nil {
2171+ ms.StoreMessageInfo(mi)
2172+ }
2173+ return ms
2174+ }
2175+ return mi.MessageOf(x)
2176+}
2177+
2178+// Deprecated: Use ResolveActionsRequest.ProtoReflect.Descriptor instead.
2179+func (*ResolveActionsRequest) Descriptor() ([]byte, []int) {
2180+ return file_ermite_runner_proto_rawDescGZIP(), []int{22}
2181+}
2182+
2183+func (x *ResolveActionsRequest) GetJobId() string {
2184+ if x != nil {
2185+ return x.JobId
2186+ }
2187+ return ""
2188+}
2189+
2190+func (x *ResolveActionsRequest) GetRefs() []*ActionRef {
2191+ if x != nil {
2192+ return x.Refs
2193+ }
2194+ return nil
2195+}
2196+
2197+// ResolveActionsResponse holds the resolution of each action.
2198+type ResolveActionsResponse struct {
2199+ state protoimpl.MessageState `protogen:"open.v1"`
2200+ // Actions has one entry per ActionRef of the request, in the same order.
2201+ Actions []*ResolvedAction `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"`
2202+ unknownFields protoimpl.UnknownFields
2203+ sizeCache protoimpl.SizeCache
2204+}
2205+
2206+func (x *ResolveActionsResponse) Reset() {
2207+ *x = ResolveActionsResponse{}
2208+ mi := &file_ermite_runner_proto_msgTypes[23]
2209+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2210+ ms.StoreMessageInfo(mi)
2211+}
2212+
2213+func (x *ResolveActionsResponse) String() string {
2214+ return protoimpl.X.MessageStringOf(x)
2215+}
2216+
2217+func (*ResolveActionsResponse) ProtoMessage() {}
2218+
2219+func (x *ResolveActionsResponse) ProtoReflect() protoreflect.Message {
2220+ mi := &file_ermite_runner_proto_msgTypes[23]
2221+ if x != nil {
2222+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2223+ if ms.LoadMessageInfo() == nil {
2224+ ms.StoreMessageInfo(mi)
2225+ }
2226+ return ms
2227+ }
2228+ return mi.MessageOf(x)
2229+}
2230+
2231+// Deprecated: Use ResolveActionsResponse.ProtoReflect.Descriptor instead.
2232+func (*ResolveActionsResponse) Descriptor() ([]byte, []int) {
2233+ return file_ermite_runner_proto_rawDescGZIP(), []int{23}
2234+}
2235+
2236+func (x *ResolveActionsResponse) GetActions() []*ResolvedAction {
2237+ if x != nil {
2238+ return x.Actions
2239+ }
2240+ return nil
2241+}
2242+
2243+// ResolvedAction is where to download one action, or why it cannot be.
2244+type ResolvedAction struct {
2245+ state protoimpl.MessageState `protogen:"open.v1"`
2246+ // Ref is the ActionRef.uses of the request, unchanged.
2247+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
2248+ // NameWithOwner is the repository of the action, "owner/repo", with the
2249+ // case of the repository as the source gives it. Empty when error is set.
2250+ NameWithOwner string `protobuf:"bytes,2,opt,name=name_with_owner,json=nameWithOwner,proto3" json:"name_with_owner,omitempty"`
2251+ // Path is the sub-path of the action inside the repository, without leading
2252+ // or trailing slash: "path/to/action" for "owner/repo/path/to/action@ref".
2253+ // Empty for an action at the root of the repository.
2254+ Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
2255+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
2256+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
2257+ // to, not the tag object). Empty when error is set.
2258+ ResolvedSha string `protobuf:"bytes,4,opt,name=resolved_sha,json=resolvedSha,proto3" json:"resolved_sha,omitempty"`
2259+ // TarballUrl is where to download the archive of the repository at
2260+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
2261+ // runner downloads it from the sandbox. Empty when error is set.
2262+ TarballUrl string `protobuf:"bytes,5,opt,name=tarball_url,json=tarballUrl,proto3" json:"tarball_url,omitempty"`
2263+ // Token authenticates the download: the runner sends it as "Authorization:
2264+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
2265+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
2266+ // valid until the job ends, so a job can use an action of another private
2267+ // repository of the server that its own repository token cannot read. It is
2268+ // a secret: the runner masks it, and neither the runner nor the server logs
2269+ // it.
2270+ Token string `protobuf:"bytes,6,opt,name=token,proto3" json:"token,omitempty"`
2271+ // Source is where the action was found. UNSPECIFIED when error is set.
2272+ Source ActionSource `protobuf:"varint,7,opt,name=source,proto3,enum=ermite.ActionSource" json:"source,omitempty"`
2273+ // Error is why the reference could not be resolved, in the words of GitHub
2274+ // for the same failure. Empty when the action was resolved, in which case
2275+ // the other fields describe it.
2276+ Error string `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"`
2277+ unknownFields protoimpl.UnknownFields
2278+ sizeCache protoimpl.SizeCache
2279+}
2280+
2281+func (x *ResolvedAction) Reset() {
2282+ *x = ResolvedAction{}
2283+ mi := &file_ermite_runner_proto_msgTypes[24]
2284+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2285+ ms.StoreMessageInfo(mi)
2286+}
2287+
2288+func (x *ResolvedAction) String() string {
2289+ return protoimpl.X.MessageStringOf(x)
2290+}
2291+
2292+func (*ResolvedAction) ProtoMessage() {}
2293+
2294+func (x *ResolvedAction) ProtoReflect() protoreflect.Message {
2295+ mi := &file_ermite_runner_proto_msgTypes[24]
2296+ if x != nil {
2297+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2298+ if ms.LoadMessageInfo() == nil {
2299+ ms.StoreMessageInfo(mi)
2300+ }
2301+ return ms
2302+ }
2303+ return mi.MessageOf(x)
2304+}
2305+
2306+// Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead.
2307+func (*ResolvedAction) Descriptor() ([]byte, []int) {
2308+ return file_ermite_runner_proto_rawDescGZIP(), []int{24}
2309+}
2310+
2311+func (x *ResolvedAction) GetRef() string {
2312+ if x != nil {
2313+ return x.Ref
2314+ }
2315+ return ""
2316+}
2317+
2318+func (x *ResolvedAction) GetNameWithOwner() string {
2319+ if x != nil {
2320+ return x.NameWithOwner
2321+ }
2322+ return ""
2323+}
2324+
2325+func (x *ResolvedAction) GetPath() string {
2326+ if x != nil {
2327+ return x.Path
2328+ }
2329+ return ""
2330+}
2331+
2332+func (x *ResolvedAction) GetResolvedSha() string {
2333+ if x != nil {
2334+ return x.ResolvedSha
2335+ }
2336+ return ""
2337+}
2338+
2339+func (x *ResolvedAction) GetTarballUrl() string {
2340+ if x != nil {
2341+ return x.TarballUrl
2342+ }
2343+ return ""
2344+}
2345+
2346+func (x *ResolvedAction) GetToken() string {
2347+ if x != nil {
2348+ return x.Token
2349+ }
2350+ return ""
2351+}
2352+
2353+func (x *ResolvedAction) GetSource() ActionSource {
2354+ if x != nil {
2355+ return x.Source
2356+ }
2357+ return ActionSource_ACTION_SOURCE_UNSPECIFIED
2358+}
2359+
2360+func (x *ResolvedAction) GetError() string {
2361+ if x != nil {
2362+ return x.Error
2363+ }
2364+ return ""
2365+}
2366+
2367+// UploadSummaryRequest carries the job summary of one step.
2368+type UploadSummaryRequest struct {
2369+ state protoimpl.MessageState `protogen:"open.v1"`
2370+ // JobId is the Job.job_id. It must be the job of the token.
2371+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2372+ // StepNumber is the number of the step that wrote the summary (see
2373+ // StepUpdate.number), from 1 to 1,000.
2374+ StepNumber int32 `protobuf:"varint,2,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2375+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
2376+ // bytes). Empty removes the summary of the step.
2377+ Markdown string `protobuf:"bytes,3,opt,name=markdown,proto3" json:"markdown,omitempty"`
2378+ unknownFields protoimpl.UnknownFields
2379+ sizeCache protoimpl.SizeCache
2380+}
2381+
2382+func (x *UploadSummaryRequest) Reset() {
2383+ *x = UploadSummaryRequest{}
2384+ mi := &file_ermite_runner_proto_msgTypes[25]
2385+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2386+ ms.StoreMessageInfo(mi)
2387+}
2388+
2389+func (x *UploadSummaryRequest) String() string {
2390+ return protoimpl.X.MessageStringOf(x)
2391+}
2392+
2393+func (*UploadSummaryRequest) ProtoMessage() {}
2394+
2395+func (x *UploadSummaryRequest) ProtoReflect() protoreflect.Message {
2396+ mi := &file_ermite_runner_proto_msgTypes[25]
2397+ if x != nil {
2398+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2399+ if ms.LoadMessageInfo() == nil {
2400+ ms.StoreMessageInfo(mi)
2401+ }
2402+ return ms
2403+ }
2404+ return mi.MessageOf(x)
2405+}
2406+
2407+// Deprecated: Use UploadSummaryRequest.ProtoReflect.Descriptor instead.
2408+func (*UploadSummaryRequest) Descriptor() ([]byte, []int) {
2409+ return file_ermite_runner_proto_rawDescGZIP(), []int{25}
2410+}
2411+
2412+func (x *UploadSummaryRequest) GetJobId() string {
2413+ if x != nil {
2414+ return x.JobId
2415+ }
2416+ return ""
2417+}
2418+
2419+func (x *UploadSummaryRequest) GetStepNumber() int32 {
2420+ if x != nil {
2421+ return x.StepNumber
2422+ }
2423+ return 0
2424+}
2425+
2426+func (x *UploadSummaryRequest) GetMarkdown() string {
2427+ if x != nil {
2428+ return x.Markdown
2429+ }
2430+ return ""
2431+}
2432+
2433+// UploadSummaryResponse is empty.
2434+type UploadSummaryResponse struct {
2435+ state protoimpl.MessageState `protogen:"open.v1"`
2436+ unknownFields protoimpl.UnknownFields
2437+ sizeCache protoimpl.SizeCache
2438+}
2439+
2440+func (x *UploadSummaryResponse) Reset() {
2441+ *x = UploadSummaryResponse{}
2442+ mi := &file_ermite_runner_proto_msgTypes[26]
2443+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2444+ ms.StoreMessageInfo(mi)
2445+}
2446+
2447+func (x *UploadSummaryResponse) String() string {
2448+ return protoimpl.X.MessageStringOf(x)
2449+}
2450+
2451+func (*UploadSummaryResponse) ProtoMessage() {}
2452+
2453+func (x *UploadSummaryResponse) ProtoReflect() protoreflect.Message {
2454+ mi := &file_ermite_runner_proto_msgTypes[26]
2455+ if x != nil {
2456+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2457+ if ms.LoadMessageInfo() == nil {
2458+ ms.StoreMessageInfo(mi)
2459+ }
2460+ return ms
2461+ }
2462+ return mi.MessageOf(x)
2463+}
2464+
2465+// Deprecated: Use UploadSummaryResponse.ProtoReflect.Descriptor instead.
2466+func (*UploadSummaryResponse) Descriptor() ([]byte, []int) {
2467+ return file_ermite_runner_proto_rawDescGZIP(), []int{26}
2468+}
2469+
17912470 var File_ermite_runner_proto protoreflect.FileDescriptor
17922471
17932472 const file_ermite_runner_proto_rawDesc = "" +
@@ -1810,7 +2489,7 @@ const file_ermite_runner_proto_rawDesc = "" +
18102489 "\x10FetchJobResponse\x12\x1d\n" +
18112490 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +
18122491 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +
1813- "retryAfter\"\xfa\x02\n" +
2492+ "retryAfter\"\x9d\x03\n" +
18142493 "\x03Job\x12\x15\n" +
18152494 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +
18162495 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
@@ -1826,10 +2505,12 @@ const file_ermite_runner_proto_rawDesc = "" +
18262505 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +
18272506 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +
18282507 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +
1829- "\x03ref\x18\x0e \x01(\tR\x03ref\"S\n" +
2508+ "\x03ref\x18\x0e \x01(\tR\x03ref\x12!\n" +
2509+ "\fgithub_token\x18\x0f \x01(\tR\vgithubToken\"\x89\x01\n" +
18302510 "\x10UpdateJobRequest\x12\x15\n" +
18312511 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +
1832- "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\"\x91\x02\n" +
2512+ "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2513+ "\vannotations\x18\x03 \x03(\v2\x12.ermite.AnnotationR\vannotations\"\xc1\x02\n" +
18332514 "\n" +
18342515 "StepUpdate\x12\x16\n" +
18352516 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +
@@ -1840,8 +2521,9 @@ const file_ermite_runner_proto_rawDesc = "" +
18402521 "conclusion\x129\n" +
18412522 "\n" +
18422523 "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" +
2524+ "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12.\n" +
2525+ "\aoutcome\x18\a \x01(\x0e2\x14.ermite.CiConclusionR\aoutcome\"\x13\n" +
2526+ "\x11UpdateJobResponse\"\xe9\x02\n" +
18452527 "\x12CompleteJobRequest\x12\x15\n" +
18462528 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +
18472529 "\n" +
@@ -1849,7 +2531,8 @@ const file_ermite_runner_proto_rawDesc = "" +
18492531 "conclusion\x12A\n" +
18502532 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +
18512533 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +
1852- "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x1a:\n" +
2534+ "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2535+ "\vannotations\x18\x06 \x03(\v2\x12.ermite.AnnotationR\vannotations\x1a:\n" +
18532536 "\fOutputsEntry\x12\x10\n" +
18542537 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
18552538 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +
@@ -1890,7 +2573,44 @@ const file_ermite_runner_proto_rawDesc = "" +
18902573 "\rCancelRequest\x12,\n" +
18912574 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +
18922575 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +
1893- "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt*o\n" +
2576+ "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt\"\x9c\x02\n" +
2577+ "\n" +
2578+ "Annotation\x12-\n" +
2579+ "\x05level\x18\x01 \x01(\x0e2\x17.ermite.AnnotationLevelR\x05level\x12\x14\n" +
2580+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x18\n" +
2581+ "\amessage\x18\x03 \x01(\tR\amessage\x12\x12\n" +
2582+ "\x04file\x18\x04 \x01(\tR\x04file\x12\x1d\n" +
2583+ "\n" +
2584+ "start_line\x18\x05 \x01(\x05R\tstartLine\x12\x19\n" +
2585+ "\bend_line\x18\x06 \x01(\x05R\aendLine\x12!\n" +
2586+ "\fstart_column\x18\a \x01(\x05R\vstartColumn\x12\x1d\n" +
2587+ "\n" +
2588+ "end_column\x18\b \x01(\x05R\tendColumn\x12\x1f\n" +
2589+ "\vstep_number\x18\t \x01(\x05R\n" +
2590+ "stepNumber\"\x1f\n" +
2591+ "\tActionRef\x12\x12\n" +
2592+ "\x04uses\x18\x01 \x01(\tR\x04uses\"U\n" +
2593+ "\x15ResolveActionsRequest\x12\x15\n" +
2594+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12%\n" +
2595+ "\x04refs\x18\x02 \x03(\v2\x11.ermite.ActionRefR\x04refs\"J\n" +
2596+ "\x16ResolveActionsResponse\x120\n" +
2597+ "\aactions\x18\x01 \x03(\v2\x16.ermite.ResolvedActionR\aactions\"\xfc\x01\n" +
2598+ "\x0eResolvedAction\x12\x10\n" +
2599+ "\x03ref\x18\x01 \x01(\tR\x03ref\x12&\n" +
2600+ "\x0fname_with_owner\x18\x02 \x01(\tR\rnameWithOwner\x12\x12\n" +
2601+ "\x04path\x18\x03 \x01(\tR\x04path\x12!\n" +
2602+ "\fresolved_sha\x18\x04 \x01(\tR\vresolvedSha\x12\x1f\n" +
2603+ "\vtarball_url\x18\x05 \x01(\tR\n" +
2604+ "tarballUrl\x12\x14\n" +
2605+ "\x05token\x18\x06 \x01(\tR\x05token\x12,\n" +
2606+ "\x06source\x18\a \x01(\x0e2\x14.ermite.ActionSourceR\x06source\x12\x14\n" +
2607+ "\x05error\x18\b \x01(\tR\x05error\"j\n" +
2608+ "\x14UploadSummaryRequest\x12\x15\n" +
2609+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
2610+ "\vstep_number\x18\x02 \x01(\x05R\n" +
2611+ "stepNumber\x12\x1a\n" +
2612+ "\bmarkdown\x18\x03 \x01(\tR\bmarkdown\"\x17\n" +
2613+ "\x15UploadSummaryResponse*o\n" +
18942614 "\bCiStatus\x12\x19\n" +
18952615 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +
18962616 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +
@@ -1919,7 +2639,16 @@ const file_ermite_runner_proto_rawDesc = "" +
19192639 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +
19202640 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +
19212641 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +
1922- "\x15CANCEL_REASON_TIMEOUT\x10\x032\xee\x03\n" +
2642+ "\x15CANCEL_REASON_TIMEOUT\x10\x03*\x8c\x01\n" +
2643+ "\x0fAnnotationLevel\x12 \n" +
2644+ "\x1cANNOTATION_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n" +
2645+ "\x17ANNOTATION_LEVEL_NOTICE\x10\x01\x12\x1c\n" +
2646+ "\x18ANNOTATION_LEVEL_WARNING\x10\x02\x12\x1c\n" +
2647+ "\x18ANNOTATION_LEVEL_FAILURE\x10\x03*a\n" +
2648+ "\fActionSource\x12\x1d\n" +
2649+ "\x19ACTION_SOURCE_UNSPECIFIED\x10\x00\x12\x18\n" +
2650+ "\x14ACTION_SOURCE_GITHUB\x10\x01\x12\x18\n" +
2651+ "\x14ACTION_SOURCE_ERMITE\x10\x022\x8d\x05\n" +
19232652 "\rRunnerService\x12O\n" +
19242653 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +
19252654 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +
@@ -1927,7 +2656,9 @@ const file_ermite_runner_proto_rawDesc = "" +
19272656 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +
19282657 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +
19292658 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +
1930- "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponseBr\n" +
2659+ "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponse\x12O\n" +
2660+ "\x0eResolveActions\x12\x1d.ermite.ResolveActionsRequest\x1a\x1e.ermite.ResolveActionsResponse\x12L\n" +
2661+ "\rUploadSummary\x12\x1c.ermite.UploadSummaryRequest\x1a\x1d.ermite.UploadSummaryResponseBr\n" +
19312662 "\n" +
19322663 "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"
19332664
@@ -1943,78 +2674,98 @@ func file_ermite_runner_proto_rawDescGZIP() []byte {
19432674 return file_ermite_runner_proto_rawDescData
19442675 }
19452676
1946-var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
1947-var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
2677+var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
2678+var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
19482679 var file_ermite_runner_proto_goTypes = []any{
19492680 (CiStatus)(0), // 0: ermite.CiStatus
19502681 (CiConclusion)(0), // 1: ermite.CiConclusion
19512682 (StepState)(0), // 2: ermite.StepState
19522683 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation
19532684 (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
2685+ (AnnotationLevel)(0), // 5: ermite.AnnotationLevel
2686+ (ActionSource)(0), // 6: ermite.ActionSource
2687+ (*RegisterRunnerRequest)(nil), // 7: ermite.RegisterRunnerRequest
2688+ (*RegisterRunnerResponse)(nil), // 8: ermite.RegisterRunnerResponse
2689+ (*FetchJobRequest)(nil), // 9: ermite.FetchJobRequest
2690+ (*FetchJobResponse)(nil), // 10: ermite.FetchJobResponse
2691+ (*Job)(nil), // 11: ermite.Job
2692+ (*UpdateJobRequest)(nil), // 12: ermite.UpdateJobRequest
2693+ (*StepUpdate)(nil), // 13: ermite.StepUpdate
2694+ (*UpdateJobResponse)(nil), // 14: ermite.UpdateJobResponse
2695+ (*CompleteJobRequest)(nil), // 15: ermite.CompleteJobRequest
2696+ (*CompleteJobResponse)(nil), // 16: ermite.CompleteJobResponse
2697+ (*JobEnded)(nil), // 17: ermite.JobEnded
2698+ (*AppendLogRequest)(nil), // 18: ermite.AppendLogRequest
2699+ (*LogLine)(nil), // 19: ermite.LogLine
2700+ (*AppendLogResponse)(nil), // 20: ermite.AppendLogResponse
2701+ (*HeartbeatRequest)(nil), // 21: ermite.HeartbeatRequest
2702+ (*HeartbeatResponse)(nil), // 22: ermite.HeartbeatResponse
2703+ (*WatchJobRequest)(nil), // 23: ermite.WatchJobRequest
2704+ (*WatchJobResponse)(nil), // 24: ermite.WatchJobResponse
2705+ (*Keepalive)(nil), // 25: ermite.Keepalive
2706+ (*CancelRequest)(nil), // 26: ermite.CancelRequest
2707+ (*Annotation)(nil), // 27: ermite.Annotation
2708+ (*ActionRef)(nil), // 28: ermite.ActionRef
2709+ (*ResolveActionsRequest)(nil), // 29: ermite.ResolveActionsRequest
2710+ (*ResolveActionsResponse)(nil), // 30: ermite.ResolveActionsResponse
2711+ (*ResolvedAction)(nil), // 31: ermite.ResolvedAction
2712+ (*UploadSummaryRequest)(nil), // 32: ermite.UploadSummaryRequest
2713+ (*UploadSummaryResponse)(nil), // 33: ermite.UploadSummaryResponse
2714+ nil, // 34: ermite.CompleteJobRequest.OutputsEntry
2715+ (*durationpb.Duration)(nil), // 35: google.protobuf.Duration
2716+ (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp
19772717 }
19782718 var file_ermite_runner_proto_depIdxs = []int32{
19792719 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
2720+ 11, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job
2721+ 35, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration
2722+ 13, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate
2723+ 27, // 4: ermite.UpdateJobRequest.annotations:type_name -> ermite.Annotation
2724+ 2, // 5: ermite.StepUpdate.state:type_name -> ermite.StepState
2725+ 1, // 6: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion
2726+ 36, // 7: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp
2727+ 36, // 8: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp
2728+ 1, // 9: ermite.StepUpdate.outcome:type_name -> ermite.CiConclusion
2729+ 1, // 10: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion
2730+ 34, // 11: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry
2731+ 13, // 12: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate
2732+ 27, // 13: ermite.CompleteJobRequest.annotations:type_name -> ermite.Annotation
2733+ 1, // 14: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion
2734+ 1, // 15: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion
2735+ 19, // 16: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine
2736+ 36, // 17: ermite.LogLine.time:type_name -> google.protobuf.Timestamp
2737+ 25, // 18: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive
2738+ 26, // 19: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest
2739+ 17, // 20: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded
2740+ 4, // 21: ermite.CancelRequest.reason:type_name -> ermite.CancelReason
2741+ 36, // 22: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp
2742+ 5, // 23: ermite.Annotation.level:type_name -> ermite.AnnotationLevel
2743+ 28, // 24: ermite.ResolveActionsRequest.refs:type_name -> ermite.ActionRef
2744+ 31, // 25: ermite.ResolveActionsResponse.actions:type_name -> ermite.ResolvedAction
2745+ 6, // 26: ermite.ResolvedAction.source:type_name -> ermite.ActionSource
2746+ 7, // 27: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest
2747+ 9, // 28: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest
2748+ 12, // 29: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest
2749+ 18, // 30: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest
2750+ 21, // 31: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest
2751+ 23, // 32: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest
2752+ 15, // 33: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest
2753+ 29, // 34: ermite.RunnerService.ResolveActions:input_type -> ermite.ResolveActionsRequest
2754+ 32, // 35: ermite.RunnerService.UploadSummary:input_type -> ermite.UploadSummaryRequest
2755+ 8, // 36: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse
2756+ 10, // 37: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse
2757+ 14, // 38: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse
2758+ 20, // 39: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse
2759+ 22, // 40: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse
2760+ 24, // 41: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse
2761+ 16, // 42: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse
2762+ 30, // 43: ermite.RunnerService.ResolveActions:output_type -> ermite.ResolveActionsResponse
2763+ 33, // 44: ermite.RunnerService.UploadSummary:output_type -> ermite.UploadSummaryResponse
2764+ 36, // [36:45] is the sub-list for method output_type
2765+ 27, // [27:36] is the sub-list for method input_type
2766+ 27, // [27:27] is the sub-list for extension type_name
2767+ 27, // [27:27] is the sub-list for extension extendee
2768+ 0, // [0:27] is the sub-list for field type_name
20182769 }
20192770
20202771 func init() { file_ermite_runner_proto_init() }
@@ -2032,8 +2783,8 @@ func file_ermite_runner_proto_init() {
20322783 File: protoimpl.DescBuilder{
20332784 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
20342785 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),
2035- NumEnums: 5,
2036- NumMessages: 21,
2786+ NumEnums: 7,
2787+ NumMessages: 28,
20372788 NumExtensions: 0,
20382789 NumServices: 1,
20392790 },
@@ -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,13 @@ 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; more is invalid_argument. The server ignores them without
984+ // the feature "ci.annotations".
985+ Annotations []*Annotation `protobuf:"bytes,3,rep,name=annotations,proto3" json:"annotations,omitempty"`
847 unknownFields protoimpl.UnknownFields986 unknownFields protoimpl.UnknownFields
848 sizeCache protoimpl.SizeCache987 sizeCache protoimpl.SizeCache
849 }988 }
@@ -892,6 +1031,13 @@ func (x *UpdateJobRequest) GetSteps() []*StepUpdate {
892 return nil1031 return nil
893 }1032 }
894 1033
1034+func (x *UpdateJobRequest) GetAnnotations() []*Annotation {
1035+ if x != nil {
1036+ return x.Annotations
1037+ }
1038+ return nil
1039+}
1040+
895 // StepUpdate is the state of one step as the runner knows it.1041 // StepUpdate is the state of one step as the runner knows it.
896 type StepUpdate struct {1042 type StepUpdate struct {
897 state protoimpl.MessageState `protogen:"open.v1"`1043 state protoimpl.MessageState `protogen:"open.v1"`
@@ -913,7 +1059,15 @@ type StepUpdate struct {
913 StartedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`1059 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. Required1060 // CompletedAt is when the step ended, by the clock of the runner. Required
915 // when state is COMPLETED.1061 // when state is COMPLETED.
916- CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`1062+ CompletedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
1063+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
1064+ // "steps.<id>.outcome", whereas conclusion is the result after it
1065+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
1066+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
1067+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
1068+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
1069+ // (a runner that does not know the field).
1070+ Outcome CiConclusion `protobuf:"varint,7,opt,name=outcome,proto3,enum=ermite.CiConclusion" json:"outcome,omitempty"`
917 unknownFields protoimpl.UnknownFields1071 unknownFields protoimpl.UnknownFields
918 sizeCache protoimpl.SizeCache1072 sizeCache protoimpl.SizeCache
919 }1073 }
@@ -990,6 +1144,13 @@ func (x *StepUpdate) GetCompletedAt() *timestamppb.Timestamp {
990 return nil1144 return nil
991 }1145 }
992 1146
1147+func (x *StepUpdate) GetOutcome() CiConclusion {
1148+ if x != nil {
1149+ return x.Outcome
1150+ }
1151+ return CiConclusion_CI_CONCLUSION_UNSPECIFIED
1152+}
1153+
993 // UpdateJobResponse is empty.1154 // UpdateJobResponse is empty.
994 type UpdateJobResponse struct {1155 type UpdateJobResponse struct {
995 state protoimpl.MessageState `protogen:"open.v1"`1156 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1054,7 +1215,12 @@ type CompleteJobRequest struct {
1054 RunnerShutdown bool `protobuf:"varint,4,opt,name=runner_shutdown,json=runnerShutdown,proto3" json:"runner_shutdown,omitempty"`1215 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,1216 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
1056 // applied in the same atomic step as the conclusion.1217 // applied in the same atomic step as the conclusion.
1057- Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`1218+ Steps []*StepUpdate `protobuf:"bytes,5,rep,name=steps,proto3" json:"steps,omitempty"`
1219+ // Annotations are those of the steps that changed since the last call, with
1220+ // the rules of UpdateJobRequest.annotations (all the annotations of each
1221+ // step named). The server ignores them without the feature
1222+ // "ci.annotations".
1223+ Annotations []*Annotation `protobuf:"bytes,6,rep,name=annotations,proto3" json:"annotations,omitempty"`
1058 unknownFields protoimpl.UnknownFields1224 unknownFields protoimpl.UnknownFields
1059 sizeCache protoimpl.SizeCache1225 sizeCache protoimpl.SizeCache
1060 }1226 }
@@ -1124,6 +1290,13 @@ func (x *CompleteJobRequest) GetSteps() []*StepUpdate {
1124 return nil1290 return nil
1125 }1291 }
1126 1292
1293+func (x *CompleteJobRequest) GetAnnotations() []*Annotation {
1294+ if x != nil {
1295+ return x.Annotations
1296+ }
1297+ return nil
1298+}
1299+
1127 // CompleteJobResponse is the stored result of a job.1300 // CompleteJobResponse is the stored result of a job.
1128 type CompleteJobResponse struct {1301 type CompleteJobResponse struct {
1129 state protoimpl.MessageState `protogen:"open.v1"`1302 state protoimpl.MessageState `protogen:"open.v1"`
@@ -1788,6 +1961,512 @@ func (x *CancelRequest) GetRequestedAt() *timestamppb.Timestamp {
1788 return nil1961 return nil
1789 }1962 }
1790 1963
1964+// Annotation is a message attached to a step, and optionally to a place in a
1965+// file of the repository, like an annotation of a GitHub check run. The runner
1966+// produces them from the workflow commands ::notice, ::warning and ::error and
1967+// from problem matchers, after masking.
1968+//
1969+// The runner sends at most 10 annotations of each level per step (the ones
1970+// beyond only reach the log) and the server rejects more.
1971+type Annotation struct {
1972+ state protoimpl.MessageState `protogen:"open.v1"`
1973+ // Level is the severity. Required.
1974+ Level AnnotationLevel `protobuf:"varint,1,opt,name=level,proto3,enum=ermite.AnnotationLevel" json:"level,omitempty"`
1975+ // Title is the optional title. Empty when not given.
1976+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
1977+ // Message is the text, at most 4,096 characters (the runner cuts longer
1978+ // ones). Required, not empty.
1979+ Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
1980+ // File is the path the annotation is about, relative to the repository when
1981+ // the runner can tell, else as given. Empty when the annotation is not about
1982+ // a file.
1983+ File string `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
1984+ // StartLine is the first line, counted from 1. 0 when not given.
1985+ StartLine int32 `protobuf:"varint,5,opt,name=start_line,json=startLine,proto3" json:"start_line,omitempty"`
1986+ // EndLine is the last line, counted from 1, not before start_line. 0 when
1987+ // not given.
1988+ EndLine int32 `protobuf:"varint,6,opt,name=end_line,json=endLine,proto3" json:"end_line,omitempty"`
1989+ // StartColumn is the first column, counted from 1. 0 when not given.
1990+ StartColumn int32 `protobuf:"varint,7,opt,name=start_column,json=startColumn,proto3" json:"start_column,omitempty"`
1991+ // EndColumn is the last column, counted from 1. 0 when not given.
1992+ EndColumn int32 `protobuf:"varint,8,opt,name=end_column,json=endColumn,proto3" json:"end_column,omitempty"`
1993+ // StepNumber is the number of the step that produced it (see
1994+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
1995+ // composite action belongs to the step of the workflow that uses the action.
1996+ StepNumber int32 `protobuf:"varint,9,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
1997+ unknownFields protoimpl.UnknownFields
1998+ sizeCache protoimpl.SizeCache
1999+}
2000+
2001+func (x *Annotation) Reset() {
2002+ *x = Annotation{}
2003+ mi := &file_ermite_runner_proto_msgTypes[20]
2004+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2005+ ms.StoreMessageInfo(mi)
2006+}
2007+
2008+func (x *Annotation) String() string {
2009+ return protoimpl.X.MessageStringOf(x)
2010+}
2011+
2012+func (*Annotation) ProtoMessage() {}
2013+
2014+func (x *Annotation) ProtoReflect() protoreflect.Message {
2015+ mi := &file_ermite_runner_proto_msgTypes[20]
2016+ if x != nil {
2017+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2018+ if ms.LoadMessageInfo() == nil {
2019+ ms.StoreMessageInfo(mi)
2020+ }
2021+ return ms
2022+ }
2023+ return mi.MessageOf(x)
2024+}
2025+
2026+// Deprecated: Use Annotation.ProtoReflect.Descriptor instead.
2027+func (*Annotation) Descriptor() ([]byte, []int) {
2028+ return file_ermite_runner_proto_rawDescGZIP(), []int{20}
2029+}
2030+
2031+func (x *Annotation) GetLevel() AnnotationLevel {
2032+ if x != nil {
2033+ return x.Level
2034+ }
2035+ return AnnotationLevel_ANNOTATION_LEVEL_UNSPECIFIED
2036+}
2037+
2038+func (x *Annotation) GetTitle() string {
2039+ if x != nil {
2040+ return x.Title
2041+ }
2042+ return ""
2043+}
2044+
2045+func (x *Annotation) GetMessage() string {
2046+ if x != nil {
2047+ return x.Message
2048+ }
2049+ return ""
2050+}
2051+
2052+func (x *Annotation) GetFile() string {
2053+ if x != nil {
2054+ return x.File
2055+ }
2056+ return ""
2057+}
2058+
2059+func (x *Annotation) GetStartLine() int32 {
2060+ if x != nil {
2061+ return x.StartLine
2062+ }
2063+ return 0
2064+}
2065+
2066+func (x *Annotation) GetEndLine() int32 {
2067+ if x != nil {
2068+ return x.EndLine
2069+ }
2070+ return 0
2071+}
2072+
2073+func (x *Annotation) GetStartColumn() int32 {
2074+ if x != nil {
2075+ return x.StartColumn
2076+ }
2077+ return 0
2078+}
2079+
2080+func (x *Annotation) GetEndColumn() int32 {
2081+ if x != nil {
2082+ return x.EndColumn
2083+ }
2084+ return 0
2085+}
2086+
2087+func (x *Annotation) GetStepNumber() int32 {
2088+ if x != nil {
2089+ return x.StepNumber
2090+ }
2091+ return 0
2092+}
2093+
2094+// ActionRef is an action to resolve.
2095+type ActionRef struct {
2096+ state protoimpl.MessageState `protogen:"open.v1"`
2097+ // Uses is the value of "uses" as written, after expression evaluation, for
2098+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
2099+ Uses string `protobuf:"bytes,1,opt,name=uses,proto3" json:"uses,omitempty"`
2100+ unknownFields protoimpl.UnknownFields
2101+ sizeCache protoimpl.SizeCache
2102+}
2103+
2104+func (x *ActionRef) Reset() {
2105+ *x = ActionRef{}
2106+ mi := &file_ermite_runner_proto_msgTypes[21]
2107+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2108+ ms.StoreMessageInfo(mi)
2109+}
2110+
2111+func (x *ActionRef) String() string {
2112+ return protoimpl.X.MessageStringOf(x)
2113+}
2114+
2115+func (*ActionRef) ProtoMessage() {}
2116+
2117+func (x *ActionRef) ProtoReflect() protoreflect.Message {
2118+ mi := &file_ermite_runner_proto_msgTypes[21]
2119+ if x != nil {
2120+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2121+ if ms.LoadMessageInfo() == nil {
2122+ ms.StoreMessageInfo(mi)
2123+ }
2124+ return ms
2125+ }
2126+ return mi.MessageOf(x)
2127+}
2128+
2129+// Deprecated: Use ActionRef.ProtoReflect.Descriptor instead.
2130+func (*ActionRef) Descriptor() ([]byte, []int) {
2131+ return file_ermite_runner_proto_rawDescGZIP(), []int{21}
2132+}
2133+
2134+func (x *ActionRef) GetUses() string {
2135+ if x != nil {
2136+ return x.Uses
2137+ }
2138+ return ""
2139+}
2140+
2141+// ResolveActionsRequest lists the actions to resolve.
2142+type ResolveActionsRequest struct {
2143+ state protoimpl.MessageState `protogen:"open.v1"`
2144+ // JobId is the Job.job_id. It must be the job of the token.
2145+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2146+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
2147+ // answered one by one.
2148+ Refs []*ActionRef `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"`
2149+ unknownFields protoimpl.UnknownFields
2150+ sizeCache protoimpl.SizeCache
2151+}
2152+
2153+func (x *ResolveActionsRequest) Reset() {
2154+ *x = ResolveActionsRequest{}
2155+ mi := &file_ermite_runner_proto_msgTypes[22]
2156+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2157+ ms.StoreMessageInfo(mi)
2158+}
2159+
2160+func (x *ResolveActionsRequest) String() string {
2161+ return protoimpl.X.MessageStringOf(x)
2162+}
2163+
2164+func (*ResolveActionsRequest) ProtoMessage() {}
2165+
2166+func (x *ResolveActionsRequest) ProtoReflect() protoreflect.Message {
2167+ mi := &file_ermite_runner_proto_msgTypes[22]
2168+ if x != nil {
2169+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2170+ if ms.LoadMessageInfo() == nil {
2171+ ms.StoreMessageInfo(mi)
2172+ }
2173+ return ms
2174+ }
2175+ return mi.MessageOf(x)
2176+}
2177+
2178+// Deprecated: Use ResolveActionsRequest.ProtoReflect.Descriptor instead.
2179+func (*ResolveActionsRequest) Descriptor() ([]byte, []int) {
2180+ return file_ermite_runner_proto_rawDescGZIP(), []int{22}
2181+}
2182+
2183+func (x *ResolveActionsRequest) GetJobId() string {
2184+ if x != nil {
2185+ return x.JobId
2186+ }
2187+ return ""
2188+}
2189+
2190+func (x *ResolveActionsRequest) GetRefs() []*ActionRef {
2191+ if x != nil {
2192+ return x.Refs
2193+ }
2194+ return nil
2195+}
2196+
2197+// ResolveActionsResponse holds the resolution of each action.
2198+type ResolveActionsResponse struct {
2199+ state protoimpl.MessageState `protogen:"open.v1"`
2200+ // Actions has one entry per ActionRef of the request, in the same order.
2201+ Actions []*ResolvedAction `protobuf:"bytes,1,rep,name=actions,proto3" json:"actions,omitempty"`
2202+ unknownFields protoimpl.UnknownFields
2203+ sizeCache protoimpl.SizeCache
2204+}
2205+
2206+func (x *ResolveActionsResponse) Reset() {
2207+ *x = ResolveActionsResponse{}
2208+ mi := &file_ermite_runner_proto_msgTypes[23]
2209+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2210+ ms.StoreMessageInfo(mi)
2211+}
2212+
2213+func (x *ResolveActionsResponse) String() string {
2214+ return protoimpl.X.MessageStringOf(x)
2215+}
2216+
2217+func (*ResolveActionsResponse) ProtoMessage() {}
2218+
2219+func (x *ResolveActionsResponse) ProtoReflect() protoreflect.Message {
2220+ mi := &file_ermite_runner_proto_msgTypes[23]
2221+ if x != nil {
2222+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2223+ if ms.LoadMessageInfo() == nil {
2224+ ms.StoreMessageInfo(mi)
2225+ }
2226+ return ms
2227+ }
2228+ return mi.MessageOf(x)
2229+}
2230+
2231+// Deprecated: Use ResolveActionsResponse.ProtoReflect.Descriptor instead.
2232+func (*ResolveActionsResponse) Descriptor() ([]byte, []int) {
2233+ return file_ermite_runner_proto_rawDescGZIP(), []int{23}
2234+}
2235+
2236+func (x *ResolveActionsResponse) GetActions() []*ResolvedAction {
2237+ if x != nil {
2238+ return x.Actions
2239+ }
2240+ return nil
2241+}
2242+
2243+// ResolvedAction is where to download one action, or why it cannot be.
2244+type ResolvedAction struct {
2245+ state protoimpl.MessageState `protogen:"open.v1"`
2246+ // Ref is the ActionRef.uses of the request, unchanged.
2247+ Ref string `protobuf:"bytes,1,opt,name=ref,proto3" json:"ref,omitempty"`
2248+ // NameWithOwner is the repository of the action, "owner/repo", with the
2249+ // case of the repository as the source gives it. Empty when error is set.
2250+ NameWithOwner string `protobuf:"bytes,2,opt,name=name_with_owner,json=nameWithOwner,proto3" json:"name_with_owner,omitempty"`
2251+ // Path is the sub-path of the action inside the repository, without leading
2252+ // or trailing slash: "path/to/action" for "owner/repo/path/to/action@ref".
2253+ // Empty for an action at the root of the repository.
2254+ Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
2255+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
2256+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
2257+ // to, not the tag object). Empty when error is set.
2258+ ResolvedSha string `protobuf:"bytes,4,opt,name=resolved_sha,json=resolvedSha,proto3" json:"resolved_sha,omitempty"`
2259+ // TarballUrl is where to download the archive of the repository at
2260+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
2261+ // runner downloads it from the sandbox. Empty when error is set.
2262+ TarballUrl string `protobuf:"bytes,5,opt,name=tarball_url,json=tarballUrl,proto3" json:"tarball_url,omitempty"`
2263+ // Token authenticates the download: the runner sends it as "Authorization:
2264+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
2265+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
2266+ // valid until the job ends, so a job can use an action of another private
2267+ // repository of the server that its own repository token cannot read. It is
2268+ // a secret: the runner masks it, and neither the runner nor the server logs
2269+ // it.
2270+ Token string `protobuf:"bytes,6,opt,name=token,proto3" json:"token,omitempty"`
2271+ // Source is where the action was found. UNSPECIFIED when error is set.
2272+ Source ActionSource `protobuf:"varint,7,opt,name=source,proto3,enum=ermite.ActionSource" json:"source,omitempty"`
2273+ // Error is why the reference could not be resolved, in the words of GitHub
2274+ // for the same failure. Empty when the action was resolved, in which case
2275+ // the other fields describe it.
2276+ Error string `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"`
2277+ unknownFields protoimpl.UnknownFields
2278+ sizeCache protoimpl.SizeCache
2279+}
2280+
2281+func (x *ResolvedAction) Reset() {
2282+ *x = ResolvedAction{}
2283+ mi := &file_ermite_runner_proto_msgTypes[24]
2284+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2285+ ms.StoreMessageInfo(mi)
2286+}
2287+
2288+func (x *ResolvedAction) String() string {
2289+ return protoimpl.X.MessageStringOf(x)
2290+}
2291+
2292+func (*ResolvedAction) ProtoMessage() {}
2293+
2294+func (x *ResolvedAction) ProtoReflect() protoreflect.Message {
2295+ mi := &file_ermite_runner_proto_msgTypes[24]
2296+ if x != nil {
2297+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2298+ if ms.LoadMessageInfo() == nil {
2299+ ms.StoreMessageInfo(mi)
2300+ }
2301+ return ms
2302+ }
2303+ return mi.MessageOf(x)
2304+}
2305+
2306+// Deprecated: Use ResolvedAction.ProtoReflect.Descriptor instead.
2307+func (*ResolvedAction) Descriptor() ([]byte, []int) {
2308+ return file_ermite_runner_proto_rawDescGZIP(), []int{24}
2309+}
2310+
2311+func (x *ResolvedAction) GetRef() string {
2312+ if x != nil {
2313+ return x.Ref
2314+ }
2315+ return ""
2316+}
2317+
2318+func (x *ResolvedAction) GetNameWithOwner() string {
2319+ if x != nil {
2320+ return x.NameWithOwner
2321+ }
2322+ return ""
2323+}
2324+
2325+func (x *ResolvedAction) GetPath() string {
2326+ if x != nil {
2327+ return x.Path
2328+ }
2329+ return ""
2330+}
2331+
2332+func (x *ResolvedAction) GetResolvedSha() string {
2333+ if x != nil {
2334+ return x.ResolvedSha
2335+ }
2336+ return ""
2337+}
2338+
2339+func (x *ResolvedAction) GetTarballUrl() string {
2340+ if x != nil {
2341+ return x.TarballUrl
2342+ }
2343+ return ""
2344+}
2345+
2346+func (x *ResolvedAction) GetToken() string {
2347+ if x != nil {
2348+ return x.Token
2349+ }
2350+ return ""
2351+}
2352+
2353+func (x *ResolvedAction) GetSource() ActionSource {
2354+ if x != nil {
2355+ return x.Source
2356+ }
2357+ return ActionSource_ACTION_SOURCE_UNSPECIFIED
2358+}
2359+
2360+func (x *ResolvedAction) GetError() string {
2361+ if x != nil {
2362+ return x.Error
2363+ }
2364+ return ""
2365+}
2366+
2367+// UploadSummaryRequest carries the job summary of one step.
2368+type UploadSummaryRequest struct {
2369+ state protoimpl.MessageState `protogen:"open.v1"`
2370+ // JobId is the Job.job_id. It must be the job of the token.
2371+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
2372+ // StepNumber is the number of the step that wrote the summary (see
2373+ // StepUpdate.number), from 1 to 1,000.
2374+ StepNumber int32 `protobuf:"varint,2,opt,name=step_number,json=stepNumber,proto3" json:"step_number,omitempty"`
2375+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
2376+ // bytes). Empty removes the summary of the step.
2377+ Markdown string `protobuf:"bytes,3,opt,name=markdown,proto3" json:"markdown,omitempty"`
2378+ unknownFields protoimpl.UnknownFields
2379+ sizeCache protoimpl.SizeCache
2380+}
2381+
2382+func (x *UploadSummaryRequest) Reset() {
2383+ *x = UploadSummaryRequest{}
2384+ mi := &file_ermite_runner_proto_msgTypes[25]
2385+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2386+ ms.StoreMessageInfo(mi)
2387+}
2388+
2389+func (x *UploadSummaryRequest) String() string {
2390+ return protoimpl.X.MessageStringOf(x)
2391+}
2392+
2393+func (*UploadSummaryRequest) ProtoMessage() {}
2394+
2395+func (x *UploadSummaryRequest) ProtoReflect() protoreflect.Message {
2396+ mi := &file_ermite_runner_proto_msgTypes[25]
2397+ if x != nil {
2398+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2399+ if ms.LoadMessageInfo() == nil {
2400+ ms.StoreMessageInfo(mi)
2401+ }
2402+ return ms
2403+ }
2404+ return mi.MessageOf(x)
2405+}
2406+
2407+// Deprecated: Use UploadSummaryRequest.ProtoReflect.Descriptor instead.
2408+func (*UploadSummaryRequest) Descriptor() ([]byte, []int) {
2409+ return file_ermite_runner_proto_rawDescGZIP(), []int{25}
2410+}
2411+
2412+func (x *UploadSummaryRequest) GetJobId() string {
2413+ if x != nil {
2414+ return x.JobId
2415+ }
2416+ return ""
2417+}
2418+
2419+func (x *UploadSummaryRequest) GetStepNumber() int32 {
2420+ if x != nil {
2421+ return x.StepNumber
2422+ }
2423+ return 0
2424+}
2425+
2426+func (x *UploadSummaryRequest) GetMarkdown() string {
2427+ if x != nil {
2428+ return x.Markdown
2429+ }
2430+ return ""
2431+}
2432+
2433+// UploadSummaryResponse is empty.
2434+type UploadSummaryResponse struct {
2435+ state protoimpl.MessageState `protogen:"open.v1"`
2436+ unknownFields protoimpl.UnknownFields
2437+ sizeCache protoimpl.SizeCache
2438+}
2439+
2440+func (x *UploadSummaryResponse) Reset() {
2441+ *x = UploadSummaryResponse{}
2442+ mi := &file_ermite_runner_proto_msgTypes[26]
2443+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2444+ ms.StoreMessageInfo(mi)
2445+}
2446+
2447+func (x *UploadSummaryResponse) String() string {
2448+ return protoimpl.X.MessageStringOf(x)
2449+}
2450+
2451+func (*UploadSummaryResponse) ProtoMessage() {}
2452+
2453+func (x *UploadSummaryResponse) ProtoReflect() protoreflect.Message {
2454+ mi := &file_ermite_runner_proto_msgTypes[26]
2455+ if x != nil {
2456+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
2457+ if ms.LoadMessageInfo() == nil {
2458+ ms.StoreMessageInfo(mi)
2459+ }
2460+ return ms
2461+ }
2462+ return mi.MessageOf(x)
2463+}
2464+
2465+// Deprecated: Use UploadSummaryResponse.ProtoReflect.Descriptor instead.
2466+func (*UploadSummaryResponse) Descriptor() ([]byte, []int) {
2467+ return file_ermite_runner_proto_rawDescGZIP(), []int{26}
2468+}
2469+
1791 var File_ermite_runner_proto protoreflect.FileDescriptor2470 var File_ermite_runner_proto protoreflect.FileDescriptor
1792 2471
1793 const file_ermite_runner_proto_rawDesc = "" +2472 const file_ermite_runner_proto_rawDesc = "" +
@@ -1810,7 +2489,7 @@ const file_ermite_runner_proto_rawDesc = "" +
1810 "\x10FetchJobResponse\x12\x1d\n" +2489 "\x10FetchJobResponse\x12\x1d\n" +
1811 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +2490 "\x03job\x18\x01 \x01(\v2\v.ermite.JobR\x03job\x12:\n" +
1812 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +2491 "\vretry_after\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\n" +
1813- "retryAfter\"\xfa\x02\n" +2492+ "retryAfter\"\x9d\x03\n" +
1814 "\x03Job\x12\x15\n" +2493 "\x03Job\x12\x15\n" +
1815 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +2494 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x15\n" +
1816 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +2495 "\x06run_id\x18\x02 \x01(\x03R\x05runId\x12\x18\n" +
@@ -1826,10 +2505,12 @@ const file_ermite_runner_proto_rawDesc = "" +
1826 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +2505 "\x0ftimeout_minutes\x18\v \x01(\x05R\x0etimeoutMinutes\x12\x12\n" +
1827 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +2506 "\x04repo\x18\f \x01(\tR\x04repo\x12\x10\n" +
1828 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +2507 "\x03sha\x18\r \x01(\tR\x03sha\x12\x10\n" +
1829- "\x03ref\x18\x0e \x01(\tR\x03ref\"S\n" +2508+ "\x03ref\x18\x0e \x01(\tR\x03ref\x12!\n" +
2509+ "\fgithub_token\x18\x0f \x01(\tR\vgithubToken\"\x89\x01\n" +
1830 "\x10UpdateJobRequest\x12\x15\n" +2510 "\x10UpdateJobRequest\x12\x15\n" +
1831 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +2511 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12(\n" +
1832- "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\"\x91\x02\n" +2512+ "\x05steps\x18\x02 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2513+ "\vannotations\x18\x03 \x03(\v2\x12.ermite.AnnotationR\vannotations\"\xc1\x02\n" +
1833 "\n" +2514 "\n" +
1834 "StepUpdate\x12\x16\n" +2515 "StepUpdate\x12\x16\n" +
1835 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +2516 "\x06number\x18\x01 \x01(\x05R\x06number\x12\x12\n" +
@@ -1840,8 +2521,9 @@ const file_ermite_runner_proto_rawDesc = "" +
1840 "conclusion\x129\n" +2521 "conclusion\x129\n" +
1841 "\n" +2522 "\n" +
1842 "started_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +2523 "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" +2524+ "\fcompleted_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x12.\n" +
1844- "\x11UpdateJobResponse\"\xb3\x02\n" +2525+ "\aoutcome\x18\a \x01(\x0e2\x14.ermite.CiConclusionR\aoutcome\"\x13\n" +
2526+ "\x11UpdateJobResponse\"\xe9\x02\n" +
1845 "\x12CompleteJobRequest\x12\x15\n" +2527 "\x12CompleteJobRequest\x12\x15\n" +
1846 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +2528 "\x06job_id\x18\x01 \x01(\tR\x05jobId\x124\n" +
1847 "\n" +2529 "\n" +
@@ -1849,7 +2531,8 @@ const file_ermite_runner_proto_rawDesc = "" +
1849 "conclusion\x12A\n" +2531 "conclusion\x12A\n" +
1850 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +2532 "\aoutputs\x18\x03 \x03(\v2'.ermite.CompleteJobRequest.OutputsEntryR\aoutputs\x12'\n" +
1851 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +2533 "\x0frunner_shutdown\x18\x04 \x01(\bR\x0erunnerShutdown\x12(\n" +
1852- "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x1a:\n" +2534+ "\x05steps\x18\x05 \x03(\v2\x12.ermite.StepUpdateR\x05steps\x124\n" +
2535+ "\vannotations\x18\x06 \x03(\v2\x12.ermite.AnnotationR\vannotations\x1a:\n" +
1853 "\fOutputsEntry\x12\x10\n" +2536 "\fOutputsEntry\x12\x10\n" +
1854 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +2537 "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
1855 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +2538 "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"{\n" +
@@ -1890,7 +2573,44 @@ const file_ermite_runner_proto_rawDesc = "" +
1890 "\rCancelRequest\x12,\n" +2573 "\rCancelRequest\x12,\n" +
1891 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +2574 "\x06reason\x18\x01 \x01(\x0e2\x14.ermite.CancelReasonR\x06reason\x12\x18\n" +
1892 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +2575 "\amessage\x18\x02 \x01(\tR\amessage\x12=\n" +
1893- "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt*o\n" +2576+ "\frequested_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\vrequestedAt\"\x9c\x02\n" +
2577+ "\n" +
2578+ "Annotation\x12-\n" +
2579+ "\x05level\x18\x01 \x01(\x0e2\x17.ermite.AnnotationLevelR\x05level\x12\x14\n" +
2580+ "\x05title\x18\x02 \x01(\tR\x05title\x12\x18\n" +
2581+ "\amessage\x18\x03 \x01(\tR\amessage\x12\x12\n" +
2582+ "\x04file\x18\x04 \x01(\tR\x04file\x12\x1d\n" +
2583+ "\n" +
2584+ "start_line\x18\x05 \x01(\x05R\tstartLine\x12\x19\n" +
2585+ "\bend_line\x18\x06 \x01(\x05R\aendLine\x12!\n" +
2586+ "\fstart_column\x18\a \x01(\x05R\vstartColumn\x12\x1d\n" +
2587+ "\n" +
2588+ "end_column\x18\b \x01(\x05R\tendColumn\x12\x1f\n" +
2589+ "\vstep_number\x18\t \x01(\x05R\n" +
2590+ "stepNumber\"\x1f\n" +
2591+ "\tActionRef\x12\x12\n" +
2592+ "\x04uses\x18\x01 \x01(\tR\x04uses\"U\n" +
2593+ "\x15ResolveActionsRequest\x12\x15\n" +
2594+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12%\n" +
2595+ "\x04refs\x18\x02 \x03(\v2\x11.ermite.ActionRefR\x04refs\"J\n" +
2596+ "\x16ResolveActionsResponse\x120\n" +
2597+ "\aactions\x18\x01 \x03(\v2\x16.ermite.ResolvedActionR\aactions\"\xfc\x01\n" +
2598+ "\x0eResolvedAction\x12\x10\n" +
2599+ "\x03ref\x18\x01 \x01(\tR\x03ref\x12&\n" +
2600+ "\x0fname_with_owner\x18\x02 \x01(\tR\rnameWithOwner\x12\x12\n" +
2601+ "\x04path\x18\x03 \x01(\tR\x04path\x12!\n" +
2602+ "\fresolved_sha\x18\x04 \x01(\tR\vresolvedSha\x12\x1f\n" +
2603+ "\vtarball_url\x18\x05 \x01(\tR\n" +
2604+ "tarballUrl\x12\x14\n" +
2605+ "\x05token\x18\x06 \x01(\tR\x05token\x12,\n" +
2606+ "\x06source\x18\a \x01(\x0e2\x14.ermite.ActionSourceR\x06source\x12\x14\n" +
2607+ "\x05error\x18\b \x01(\tR\x05error\"j\n" +
2608+ "\x14UploadSummaryRequest\x12\x15\n" +
2609+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
2610+ "\vstep_number\x18\x02 \x01(\x05R\n" +
2611+ "stepNumber\x12\x1a\n" +
2612+ "\bmarkdown\x18\x03 \x01(\tR\bmarkdown\"\x17\n" +
2613+ "\x15UploadSummaryResponse*o\n" +
1894 "\bCiStatus\x12\x19\n" +2614 "\bCiStatus\x12\x19\n" +
1895 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +2615 "\x15CI_STATUS_UNSPECIFIED\x10\x00\x12\x14\n" +
1896 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +2616 "\x10CI_STATUS_QUEUED\x10\x01\x12\x19\n" +
@@ -1919,7 +2639,16 @@ const file_ermite_runner_proto_rawDesc = "" +
1919 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +2639 "\x19CANCEL_REASON_UNSPECIFIED\x10\x00\x12\x16\n" +
1920 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +2640 "\x12CANCEL_REASON_USER\x10\x01\x12\x1b\n" +
1921 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +2641 "\x17CANCEL_REASON_FAIL_FAST\x10\x02\x12\x19\n" +
1922- "\x15CANCEL_REASON_TIMEOUT\x10\x032\xee\x03\n" +2642+ "\x15CANCEL_REASON_TIMEOUT\x10\x03*\x8c\x01\n" +
2643+ "\x0fAnnotationLevel\x12 \n" +
2644+ "\x1cANNOTATION_LEVEL_UNSPECIFIED\x10\x00\x12\x1b\n" +
2645+ "\x17ANNOTATION_LEVEL_NOTICE\x10\x01\x12\x1c\n" +
2646+ "\x18ANNOTATION_LEVEL_WARNING\x10\x02\x12\x1c\n" +
2647+ "\x18ANNOTATION_LEVEL_FAILURE\x10\x03*a\n" +
2648+ "\fActionSource\x12\x1d\n" +
2649+ "\x19ACTION_SOURCE_UNSPECIFIED\x10\x00\x12\x18\n" +
2650+ "\x14ACTION_SOURCE_GITHUB\x10\x01\x12\x18\n" +
2651+ "\x14ACTION_SOURCE_ERMITE\x10\x022\x8d\x05\n" +
1923 "\rRunnerService\x12O\n" +2652 "\rRunnerService\x12O\n" +
1924 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +2653 "\x0eRegisterRunner\x12\x1d.ermite.RegisterRunnerRequest\x1a\x1e.ermite.RegisterRunnerResponse\x12=\n" +
1925 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +2654 "\bFetchJob\x12\x17.ermite.FetchJobRequest\x1a\x18.ermite.FetchJobResponse\x12@\n" +
@@ -1927,7 +2656,9 @@ const file_ermite_runner_proto_rawDesc = "" +
1927 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +2656 "\tAppendLog\x12\x18.ermite.AppendLogRequest\x1a\x19.ermite.AppendLogResponse\x12@\n" +
1928 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +2657 "\tHeartbeat\x12\x18.ermite.HeartbeatRequest\x1a\x19.ermite.HeartbeatResponse\x12?\n" +
1929 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +2658 "\bWatchJob\x12\x17.ermite.WatchJobRequest\x1a\x18.ermite.WatchJobResponse0\x01\x12F\n" +
1930- "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponseBr\n" +2659+ "\vCompleteJob\x12\x1a.ermite.CompleteJobRequest\x1a\x1b.ermite.CompleteJobResponse\x12O\n" +
2660+ "\x0eResolveActions\x12\x1d.ermite.ResolveActionsRequest\x1a\x1e.ermite.ResolveActionsResponse\x12L\n" +
2661+ "\rUploadSummary\x12\x1c.ermite.UploadSummaryRequest\x1a\x1d.ermite.UploadSummaryResponseBr\n" +
1931 "\n" +2662 "\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"2663 "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 2664
@@ -1943,78 +2674,98 @@ func file_ermite_runner_proto_rawDescGZIP() []byte {
1943 return file_ermite_runner_proto_rawDescData2674 return file_ermite_runner_proto_rawDescData
1944 }2675 }
1945 2676
1946-var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 5)2677+var file_ermite_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 7)
1947-var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 21)2678+var file_ermite_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
1948 var file_ermite_runner_proto_goTypes = []any{2679 var file_ermite_runner_proto_goTypes = []any{
1949 (CiStatus)(0), // 0: ermite.CiStatus2680 (CiStatus)(0), // 0: ermite.CiStatus
1950 (CiConclusion)(0), // 1: ermite.CiConclusion2681 (CiConclusion)(0), // 1: ermite.CiConclusion
1951 (StepState)(0), // 2: ermite.StepState2682 (StepState)(0), // 2: ermite.StepState
1952 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation2683 (RunnerIsolation)(0), // 3: ermite.RunnerIsolation
1953 (CancelReason)(0), // 4: ermite.CancelReason2684 (CancelReason)(0), // 4: ermite.CancelReason
1954- (*RegisterRunnerRequest)(nil), // 5: ermite.RegisterRunnerRequest2685+ (AnnotationLevel)(0), // 5: ermite.AnnotationLevel
1955- (*RegisterRunnerResponse)(nil), // 6: ermite.RegisterRunnerResponse2686+ (ActionSource)(0), // 6: ermite.ActionSource
1956- (*FetchJobRequest)(nil), // 7: ermite.FetchJobRequest2687+ (*RegisterRunnerRequest)(nil), // 7: ermite.RegisterRunnerRequest
1957- (*FetchJobResponse)(nil), // 8: ermite.FetchJobResponse2688+ (*RegisterRunnerResponse)(nil), // 8: ermite.RegisterRunnerResponse
1958- (*Job)(nil), // 9: ermite.Job2689+ (*FetchJobRequest)(nil), // 9: ermite.FetchJobRequest
1959- (*UpdateJobRequest)(nil), // 10: ermite.UpdateJobRequest2690+ (*FetchJobResponse)(nil), // 10: ermite.FetchJobResponse
1960- (*StepUpdate)(nil), // 11: ermite.StepUpdate2691+ (*Job)(nil), // 11: ermite.Job
1961- (*UpdateJobResponse)(nil), // 12: ermite.UpdateJobResponse2692+ (*UpdateJobRequest)(nil), // 12: ermite.UpdateJobRequest
1962- (*CompleteJobRequest)(nil), // 13: ermite.CompleteJobRequest2693+ (*StepUpdate)(nil), // 13: ermite.StepUpdate
1963- (*CompleteJobResponse)(nil), // 14: ermite.CompleteJobResponse2694+ (*UpdateJobResponse)(nil), // 14: ermite.UpdateJobResponse
1964- (*JobEnded)(nil), // 15: ermite.JobEnded2695+ (*CompleteJobRequest)(nil), // 15: ermite.CompleteJobRequest
1965- (*AppendLogRequest)(nil), // 16: ermite.AppendLogRequest2696+ (*CompleteJobResponse)(nil), // 16: ermite.CompleteJobResponse
1966- (*LogLine)(nil), // 17: ermite.LogLine2697+ (*JobEnded)(nil), // 17: ermite.JobEnded
1967- (*AppendLogResponse)(nil), // 18: ermite.AppendLogResponse2698+ (*AppendLogRequest)(nil), // 18: ermite.AppendLogRequest
1968- (*HeartbeatRequest)(nil), // 19: ermite.HeartbeatRequest2699+ (*LogLine)(nil), // 19: ermite.LogLine
1969- (*HeartbeatResponse)(nil), // 20: ermite.HeartbeatResponse2700+ (*AppendLogResponse)(nil), // 20: ermite.AppendLogResponse
1970- (*WatchJobRequest)(nil), // 21: ermite.WatchJobRequest2701+ (*HeartbeatRequest)(nil), // 21: ermite.HeartbeatRequest
1971- (*WatchJobResponse)(nil), // 22: ermite.WatchJobResponse2702+ (*HeartbeatResponse)(nil), // 22: ermite.HeartbeatResponse
1972- (*Keepalive)(nil), // 23: ermite.Keepalive2703+ (*WatchJobRequest)(nil), // 23: ermite.WatchJobRequest
1973- (*CancelRequest)(nil), // 24: ermite.CancelRequest2704+ (*WatchJobResponse)(nil), // 24: ermite.WatchJobResponse
1974- nil, // 25: ermite.CompleteJobRequest.OutputsEntry2705+ (*Keepalive)(nil), // 25: ermite.Keepalive
1975- (*durationpb.Duration)(nil), // 26: google.protobuf.Duration2706+ (*CancelRequest)(nil), // 26: ermite.CancelRequest
1976- (*timestamppb.Timestamp)(nil), // 27: google.protobuf.Timestamp2707+ (*Annotation)(nil), // 27: ermite.Annotation
2708+ (*ActionRef)(nil), // 28: ermite.ActionRef
2709+ (*ResolveActionsRequest)(nil), // 29: ermite.ResolveActionsRequest
2710+ (*ResolveActionsResponse)(nil), // 30: ermite.ResolveActionsResponse
2711+ (*ResolvedAction)(nil), // 31: ermite.ResolvedAction
2712+ (*UploadSummaryRequest)(nil), // 32: ermite.UploadSummaryRequest
2713+ (*UploadSummaryResponse)(nil), // 33: ermite.UploadSummaryResponse
2714+ nil, // 34: ermite.CompleteJobRequest.OutputsEntry
2715+ (*durationpb.Duration)(nil), // 35: google.protobuf.Duration
2716+ (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp
1977 }2717 }
1978 var file_ermite_runner_proto_depIdxs = []int32{2718 var file_ermite_runner_proto_depIdxs = []int32{
1979 3, // 0: ermite.RegisterRunnerRequest.isolation:type_name -> ermite.RunnerIsolation2719 3, // 0: ermite.RegisterRunnerRequest.isolation:type_name -> ermite.RunnerIsolation
1980- 9, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job2720+ 11, // 1: ermite.FetchJobResponse.job:type_name -> ermite.Job
1981- 26, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration2721+ 35, // 2: ermite.FetchJobResponse.retry_after:type_name -> google.protobuf.Duration
1982- 11, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate2722+ 13, // 3: ermite.UpdateJobRequest.steps:type_name -> ermite.StepUpdate
1983- 2, // 4: ermite.StepUpdate.state:type_name -> ermite.StepState2723+ 27, // 4: ermite.UpdateJobRequest.annotations:type_name -> ermite.Annotation
1984- 1, // 5: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion2724+ 2, // 5: ermite.StepUpdate.state:type_name -> ermite.StepState
1985- 27, // 6: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp2725+ 1, // 6: ermite.StepUpdate.conclusion:type_name -> ermite.CiConclusion
1986- 27, // 7: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp2726+ 36, // 7: ermite.StepUpdate.started_at:type_name -> google.protobuf.Timestamp
1987- 1, // 8: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion2727+ 36, // 8: ermite.StepUpdate.completed_at:type_name -> google.protobuf.Timestamp
1988- 25, // 9: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry2728+ 1, // 9: ermite.StepUpdate.outcome:type_name -> ermite.CiConclusion
1989- 11, // 10: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate2729+ 1, // 10: ermite.CompleteJobRequest.conclusion:type_name -> ermite.CiConclusion
1990- 1, // 11: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion2730+ 34, // 11: ermite.CompleteJobRequest.outputs:type_name -> ermite.CompleteJobRequest.OutputsEntry
1991- 1, // 12: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion2731+ 13, // 12: ermite.CompleteJobRequest.steps:type_name -> ermite.StepUpdate
1992- 17, // 13: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine2732+ 27, // 13: ermite.CompleteJobRequest.annotations:type_name -> ermite.Annotation
1993- 27, // 14: ermite.LogLine.time:type_name -> google.protobuf.Timestamp2733+ 1, // 14: ermite.CompleteJobResponse.conclusion:type_name -> ermite.CiConclusion
1994- 23, // 15: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive2734+ 1, // 15: ermite.JobEnded.conclusion:type_name -> ermite.CiConclusion
1995- 24, // 16: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest2735+ 19, // 16: ermite.AppendLogRequest.lines:type_name -> ermite.LogLine
1996- 15, // 17: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded2736+ 36, // 17: ermite.LogLine.time:type_name -> google.protobuf.Timestamp
1997- 4, // 18: ermite.CancelRequest.reason:type_name -> ermite.CancelReason2737+ 25, // 18: ermite.WatchJobResponse.keepalive:type_name -> ermite.Keepalive
1998- 27, // 19: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp2738+ 26, // 19: ermite.WatchJobResponse.cancel:type_name -> ermite.CancelRequest
1999- 5, // 20: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest2739+ 17, // 20: ermite.WatchJobResponse.ended:type_name -> ermite.JobEnded
2000- 7, // 21: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest2740+ 4, // 21: ermite.CancelRequest.reason:type_name -> ermite.CancelReason
2001- 10, // 22: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest2741+ 36, // 22: ermite.CancelRequest.requested_at:type_name -> google.protobuf.Timestamp
2002- 16, // 23: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest2742+ 5, // 23: ermite.Annotation.level:type_name -> ermite.AnnotationLevel
2003- 19, // 24: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest2743+ 28, // 24: ermite.ResolveActionsRequest.refs:type_name -> ermite.ActionRef
2004- 21, // 25: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest2744+ 31, // 25: ermite.ResolveActionsResponse.actions:type_name -> ermite.ResolvedAction
2005- 13, // 26: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest2745+ 6, // 26: ermite.ResolvedAction.source:type_name -> ermite.ActionSource
2006- 6, // 27: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse2746+ 7, // 27: ermite.RunnerService.RegisterRunner:input_type -> ermite.RegisterRunnerRequest
2007- 8, // 28: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse2747+ 9, // 28: ermite.RunnerService.FetchJob:input_type -> ermite.FetchJobRequest
2008- 12, // 29: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse2748+ 12, // 29: ermite.RunnerService.UpdateJob:input_type -> ermite.UpdateJobRequest
2009- 18, // 30: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse2749+ 18, // 30: ermite.RunnerService.AppendLog:input_type -> ermite.AppendLogRequest
2010- 20, // 31: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse2750+ 21, // 31: ermite.RunnerService.Heartbeat:input_type -> ermite.HeartbeatRequest
2011- 22, // 32: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse2751+ 23, // 32: ermite.RunnerService.WatchJob:input_type -> ermite.WatchJobRequest
2012- 14, // 33: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse2752+ 15, // 33: ermite.RunnerService.CompleteJob:input_type -> ermite.CompleteJobRequest
2013- 27, // [27:34] is the sub-list for method output_type2753+ 29, // 34: ermite.RunnerService.ResolveActions:input_type -> ermite.ResolveActionsRequest
2014- 20, // [20:27] is the sub-list for method input_type2754+ 32, // 35: ermite.RunnerService.UploadSummary:input_type -> ermite.UploadSummaryRequest
2015- 20, // [20:20] is the sub-list for extension type_name2755+ 8, // 36: ermite.RunnerService.RegisterRunner:output_type -> ermite.RegisterRunnerResponse
2016- 20, // [20:20] is the sub-list for extension extendee2756+ 10, // 37: ermite.RunnerService.FetchJob:output_type -> ermite.FetchJobResponse
2017- 0, // [0:20] is the sub-list for field type_name2757+ 14, // 38: ermite.RunnerService.UpdateJob:output_type -> ermite.UpdateJobResponse
2758+ 20, // 39: ermite.RunnerService.AppendLog:output_type -> ermite.AppendLogResponse
2759+ 22, // 40: ermite.RunnerService.Heartbeat:output_type -> ermite.HeartbeatResponse
2760+ 24, // 41: ermite.RunnerService.WatchJob:output_type -> ermite.WatchJobResponse
2761+ 16, // 42: ermite.RunnerService.CompleteJob:output_type -> ermite.CompleteJobResponse
2762+ 30, // 43: ermite.RunnerService.ResolveActions:output_type -> ermite.ResolveActionsResponse
2763+ 33, // 44: ermite.RunnerService.UploadSummary:output_type -> ermite.UploadSummaryResponse
2764+ 36, // [36:45] is the sub-list for method output_type
2765+ 27, // [27:36] is the sub-list for method input_type
2766+ 27, // [27:27] is the sub-list for extension type_name
2767+ 27, // [27:27] is the sub-list for extension extendee
2768+ 0, // [0:27] is the sub-list for field type_name
2018 }2769 }
2019 2770
2020 func init() { file_ermite_runner_proto_init() }2771 func init() { file_ermite_runner_proto_init() }
@@ -2032,8 +2783,8 @@ func file_ermite_runner_proto_init() {
2032 File: protoimpl.DescBuilder{2783 File: protoimpl.DescBuilder{
2033 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),2784 GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
2034 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),2785 RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_runner_proto_rawDesc), len(file_ermite_runner_proto_rawDesc)),
2035- NumEnums: 5,2786+ NumEnums: 7,
2036- NumMessages: 21,2787+ NumMessages: 28,
2037 NumExtensions: 0,2788 NumExtensions: 0,
2038 NumServices: 1,2789 NumServices: 1,
2039 },2790 },
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}},
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"}}},
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}},
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"}}},
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 +84 -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,21 @@ 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. Needs the same access as GetRun. Returns at most
287+ // 1,000 annotations (truncated tells). A run without annotations gives an
288+ // empty list. Only servers with the feature "ci.annotations" implement it
289+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
290+ // the job does not exist, or if the job is not a job of the run.
291+ rpc ListAnnotations(ListAnnotationsRequest) returns (ListAnnotationsResponse);
292+ // GetStepSummaries returns the job summaries (the Markdown written to
293+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
294+ // number. Needs the same access as GetJob. Only servers with the feature
295+ // "ci.summaries" implement it (unimplemented otherwise). A job without
296+ // summaries gives an empty list. Fails with not_found if the job or the
297+ // attempt does not exist.
298+ rpc GetStepSummaries(GetStepSummariesRequest) returns (GetStepSummariesResponse);
276299 // GetJobLog streams the lines of the log of a job, from a line number. The
277300 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
278301 // text each.
@@ -393,6 +416,62 @@ message GetJobResponse {
393416 RunJob job = 1;
394417 }
395418
419+// ListAnnotationsRequest selects the annotations of a run.
420+message ListAnnotationsRequest {
421+ // Repo is the repository name.
422+ string repo = 1;
423+ // RunId is the Run.id.
424+ int64 run_id = 2;
425+ // Attempt is the attempt to read. 0 means the latest.
426+ int32 attempt = 3;
427+ // JobId restricts the result to one job (RunJob.id). Empty means every job
428+ // of the run.
429+ string job_id = 4;
430+}
431+
432+// ListAnnotationsResponse holds the annotations of a run.
433+message ListAnnotationsResponse {
434+ // Annotations are the annotations, at most 1,000.
435+ repeated JobAnnotation annotations = 1;
436+ // Truncated is true when there are more annotations than annotations holds.
437+ bool truncated = 2;
438+}
439+
440+// JobAnnotation is an annotation with the job it belongs to.
441+message JobAnnotation {
442+ // JobId is the RunJob.id of the job.
443+ string job_id = 1;
444+ // Annotation is the annotation as the runner sent it, after the server
445+ // checked it. Its step_number is the step of the job.
446+ Annotation annotation = 2;
447+}
448+
449+// GetStepSummariesRequest selects a job.
450+message GetStepSummariesRequest {
451+ // Repo is the repository name.
452+ string repo = 1;
453+ // JobId is the RunJob.id.
454+ string job_id = 2;
455+ // Attempt is the RunJob.attempt to read. 0 means the latest.
456+ int32 attempt = 3;
457+}
458+
459+// GetStepSummariesResponse holds the summaries of a job.
460+message GetStepSummariesResponse {
461+ // Summaries are the summaries of the steps that have one, ordered by step
462+ // number.
463+ repeated StepSummary summaries = 1;
464+}
465+
466+// StepSummary is the job summary of one step.
467+message StepSummary {
468+ // StepNumber is the number of the step (see Step.number).
469+ int32 step_number = 1;
470+ // Markdown is the summary as uploaded, at most 1 MiB. Clients render it
471+ // safely: it is untrusted content (raw HTML and script URLs must not run).
472+ string markdown = 2;
473+}
474+
396475 // GetJobLogRequest selects the lines to stream.
397476 message GetJobLogRequest {
398477 // 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,21 @@ 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. Needs the same access as GetRun. Returns at most
287+ // 1,000 annotations (truncated tells). A run without annotations gives an
288+ // empty list. Only servers with the feature "ci.annotations" implement it
289+ // (unimplemented otherwise). Fails with not_found if the run, the attempt or
290+ // the job does not exist, or if the job is not a job of the run.
291+ rpc ListAnnotations(ListAnnotationsRequest) returns (ListAnnotationsResponse);
292+ // GetStepSummaries returns the job summaries (the Markdown written to
293+ // GITHUB_STEP_SUMMARY) of the steps of a job that have one, ordered by step
294+ // number. Needs the same access as GetJob. Only servers with the feature
295+ // "ci.summaries" implement it (unimplemented otherwise). A job without
296+ // summaries gives an empty list. Fails with not_found if the job or the
297+ // attempt does not exist.
298+ rpc GetStepSummaries(GetStepSummariesRequest) returns (GetStepSummariesResponse);
276 // GetJobLog streams the lines of the log of a job, from a line number. The299 // 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 of300 // server sends them in order in messages of at most 1,000 lines and 64 KiB of
278 // text each.301 // text each.
@@ -393,6 +416,62 @@ message GetJobResponse {
393 RunJob job = 1;416 RunJob job = 1;
394 }417 }
395 418
419+// ListAnnotationsRequest selects the annotations of a run.
420+message ListAnnotationsRequest {
421+ // Repo is the repository name.
422+ string repo = 1;
423+ // RunId is the Run.id.
424+ int64 run_id = 2;
425+ // Attempt is the attempt to read. 0 means the latest.
426+ int32 attempt = 3;
427+ // JobId restricts the result to one job (RunJob.id). Empty means every job
428+ // of the run.
429+ string job_id = 4;
430+}
431+
432+// ListAnnotationsResponse holds the annotations of a run.
433+message ListAnnotationsResponse {
434+ // Annotations are the annotations, at most 1,000.
435+ repeated JobAnnotation annotations = 1;
436+ // Truncated is true when there are more annotations than annotations holds.
437+ bool truncated = 2;
438+}
439+
440+// JobAnnotation is an annotation with the job it belongs to.
441+message JobAnnotation {
442+ // JobId is the RunJob.id of the job.
443+ string job_id = 1;
444+ // Annotation is the annotation as the runner sent it, after the server
445+ // checked it. Its step_number is the step of the job.
446+ Annotation annotation = 2;
447+}
448+
449+// GetStepSummariesRequest selects a job.
450+message GetStepSummariesRequest {
451+ // Repo is the repository name.
452+ string repo = 1;
453+ // JobId is the RunJob.id.
454+ string job_id = 2;
455+ // Attempt is the RunJob.attempt to read. 0 means the latest.
456+ int32 attempt = 3;
457+}
458+
459+// GetStepSummariesResponse holds the summaries of a job.
460+message GetStepSummariesResponse {
461+ // Summaries are the summaries of the steps that have one, ordered by step
462+ // number.
463+ repeated StepSummary summaries = 1;
464+}
465+
466+// StepSummary is the job summary of one step.
467+message StepSummary {
468+ // StepNumber is the number of the step (see Step.number).
469+ int32 step_number = 1;
470+ // Markdown is the summary as uploaded, at most 1 MiB. Clients render it
471+ // safely: it is untrusted content (raw HTML and script URLs must not run).
472+ string markdown = 2;
473+}
474+
396 // GetJobLogRequest selects the lines to stream.475 // GetJobLogRequest selects the lines to stream.
397 message GetJobLogRequest {476 message GetJobLogRequest {
398 // Repo is the repository name.477 // Repo is the repository name.
M proto/ermite/runner.proto +233 -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,16 @@ 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.
233+ //
234+ // Fails with invalid_argument if a rule is broken (including the annotation
235+ // limits), with failed_precondition if a step goes back (a COMPLETED step
236+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
237+ // failed_precondition and a JobEnded detail if the job has ended.
198238 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);
199239 // AppendLog appends lines to the log of a job. Needs the job token.
200240 //
@@ -299,9 +339,53 @@ service RunnerService {
299339 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when
300340 // they never started and the job did not end by cancellation).
301341 //
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.
342+ // Annotations are applied as in UpdateJob, together with the conclusion.
343+ // Summaries are not part of this call: a runner sends them with
344+ // UploadSummary before it.
345+ //
346+ // Fails with invalid_argument if a rule is broken (including the output and
347+ // annotation limits) and failed_precondition if a step goes back, as in
348+ // UpdateJob.
304349 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);
350+ // ResolveActions turns the "uses" of workflow and action steps into what the
351+ // runner needs to download the actions, as GitHub's action download info
352+ // does. Needs the job token; the job_id must be the one of the token. It
353+ // may be called as often as needed while the job runs (the runner calls it
354+ // once per level of composite actions, see the runner's depth limit of 9).
355+ // The runner then downloads each archive itself, from the sandbox, with the
356+ // token of the ResolvedAction when there is one.
357+ //
358+ // The response has one ResolvedAction per ActionRef, in the same order. A
359+ // reference that cannot be resolved (unknown repository, tag or branch, a
360+ // repository without access, a "uses" that GitHub itself would reject) does
361+ // not fail the call: its ResolvedAction has only ref and error, where error
362+ // is the message GitHub gives for the same failure, which the runner prints
363+ // as is. Only a failure of the call itself (credential, ended job, bad
364+ // request, server error) is an RPC error; the runner then fails the job.
365+ //
366+ // Resolution is stable for a run: the same ref resolves to the same sha for
367+ // every job and every call of one attempt of the run. A re-run attempt
368+ // resolves again.
369+ //
370+ // Fails with unauthenticated or permission_denied as the other job RPCs,
371+ // with failed_precondition and a JobEnded detail if the job has ended, and
372+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
373+ // local action ("./path") or a Docker image ("docker://"), which the runner
374+ // handles without the server.
375+ rpc ResolveActions(ResolveActionsRequest) returns (ResolveActionsResponse);
376+ // UploadSummary stores the job summary of one step: the Markdown that the
377+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
378+ // The runner masks it before sending it, and sends it after the step ended
379+ // and before CompleteJob.
380+ //
381+ // It is idempotent: the summary of a step is replaced by each call, so a
382+ // retry changes nothing, and an empty markdown removes the summary of the
383+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
384+ // clients set a message size limit above it.
385+ //
386+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
387+ // and with failed_precondition and a JobEnded detail if the job has ended.
388+ rpc UploadSummary(UploadSummaryRequest) returns (UploadSummaryResponse);
305389 }
306390
307391 // RegisterRunnerRequest describes the runner to register.
@@ -437,6 +521,18 @@ message Job {
437521 // Ref is the full ref name that triggered the run, for example
438522 // "refs/heads/main" or "refs/tags/v1.0.0".
439523 string ref = 14;
524+ // GithubToken is the job repository token, the "github.token" and
525+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
526+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
527+ // the job: the runner gives it to the sandbox (actions/checkout clones with
528+ // it). It can only read the repository of the run (read-only, whatever
529+ // "permissions:" says), and is valid from the assignment until the job ends
530+ // (it is revoked then, on cancellation and when the job is lost). It is a
531+ // secret: the runner registers it in its masker before anything runs, and
532+ // neither the runner nor the server logs it. It is shown only in this
533+ // response, or in a repeat of the same poll_id; a new assignment of the same
534+ // job has a new one. Empty from servers without the feature "ci.actions".
535+ string github_token = 15;
440536 }
441537
442538 // UpdateJobRequest reports the steps of a running job.
@@ -449,6 +545,12 @@ message UpdateJobRequest {
449545 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
450546 // the implicit "Complete job" is last.
451547 repeated StepUpdate steps = 2;
548+ // Annotations are the annotations of the steps that the call names: for
549+ // each step_number present, all the annotations of that step known so far,
550+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
551+ // and per step; more is invalid_argument. The server ignores them without
552+ // the feature "ci.annotations".
553+ repeated Annotation annotations = 3;
452554 }
453555
454556 // StepUpdate is the state of one step as the runner knows it.
@@ -472,6 +574,14 @@ message StepUpdate {
472574 // CompletedAt is when the step ended, by the clock of the runner. Required
473575 // when state is COMPLETED.
474576 google.protobuf.Timestamp completed_at = 6;
577+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
578+ // "steps.<id>.outcome", whereas conclusion is the result after it
579+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
580+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
581+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
582+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
583+ // (a runner that does not know the field).
584+ CiConclusion outcome = 7;
475585 }
476586
477587 // UpdateJobResponse is empty.
@@ -504,6 +614,11 @@ message CompleteJobRequest {
504614 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
505615 // applied in the same atomic step as the conclusion.
506616 repeated StepUpdate steps = 5;
617+ // Annotations are those of the steps that changed since the last call, with
618+ // the rules of UpdateJobRequest.annotations (all the annotations of each
619+ // step named). The server ignores them without the feature
620+ // "ci.annotations".
621+ repeated Annotation annotations = 6;
507622 }
508623
509624 // CompleteJobResponse is the stored result of a job.
@@ -620,3 +735,109 @@ message CancelRequest {
620735 // server.
621736 google.protobuf.Timestamp requested_at = 3;
622737 }
738+
739+// Annotation is a message attached to a step, and optionally to a place in a
740+// file of the repository, like an annotation of a GitHub check run. The runner
741+// produces them from the workflow commands ::notice, ::warning and ::error and
742+// from problem matchers, after masking.
743+//
744+// The runner sends at most 10 annotations of each level per step (the ones
745+// beyond only reach the log) and the server rejects more.
746+message Annotation {
747+ // Level is the severity. Required.
748+ AnnotationLevel level = 1;
749+ // Title is the optional title. Empty when not given.
750+ string title = 2;
751+ // Message is the text, at most 4,096 characters (the runner cuts longer
752+ // ones). Required, not empty.
753+ string message = 3;
754+ // File is the path the annotation is about, relative to the repository when
755+ // the runner can tell, else as given. Empty when the annotation is not about
756+ // a file.
757+ string file = 4;
758+ // StartLine is the first line, counted from 1. 0 when not given.
759+ int32 start_line = 5;
760+ // EndLine is the last line, counted from 1, not before start_line. 0 when
761+ // not given.
762+ int32 end_line = 6;
763+ // StartColumn is the first column, counted from 1. 0 when not given.
764+ int32 start_column = 7;
765+ // EndColumn is the last column, counted from 1. 0 when not given.
766+ int32 end_column = 8;
767+ // StepNumber is the number of the step that produced it (see
768+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
769+ // composite action belongs to the step of the workflow that uses the action.
770+ int32 step_number = 9;
771+}
772+
773+// ActionRef is an action to resolve.
774+message ActionRef {
775+ // Uses is the value of "uses" as written, after expression evaluation, for
776+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
777+ string uses = 1;
778+}
779+
780+// ResolveActionsRequest lists the actions to resolve.
781+message ResolveActionsRequest {
782+ // JobId is the Job.job_id. It must be the job of the token.
783+ string job_id = 1;
784+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
785+ // answered one by one.
786+ repeated ActionRef refs = 2;
787+}
788+
789+// ResolveActionsResponse holds the resolution of each action.
790+message ResolveActionsResponse {
791+ // Actions has one entry per ActionRef of the request, in the same order.
792+ repeated ResolvedAction actions = 1;
793+}
794+
795+// ResolvedAction is where to download one action, or why it cannot be.
796+message ResolvedAction {
797+ // Ref is the ActionRef.uses of the request, unchanged.
798+ string ref = 1;
799+ // NameWithOwner is the repository of the action, "owner/repo", with the
800+ // case of the repository as the source gives it. Empty when error is set.
801+ string name_with_owner = 2;
802+ // Path is the sub-path of the action inside the repository, without leading
803+ // or trailing slash: "path/to/action" for "owner/repo/path/to/action@ref".
804+ // Empty for an action at the root of the repository.
805+ string path = 3;
806+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
807+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
808+ // to, not the tag object). Empty when error is set.
809+ string resolved_sha = 4;
810+ // TarballUrl is where to download the archive of the repository at
811+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
812+ // runner downloads it from the sandbox. Empty when error is set.
813+ string tarball_url = 5;
814+ // Token authenticates the download: the runner sends it as "Authorization:
815+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
816+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
817+ // valid until the job ends, so a job can use an action of another private
818+ // repository of the server that its own repository token cannot read. It is
819+ // a secret: the runner masks it, and neither the runner nor the server logs
820+ // it.
821+ string token = 6;
822+ // Source is where the action was found. UNSPECIFIED when error is set.
823+ ActionSource source = 7;
824+ // Error is why the reference could not be resolved, in the words of GitHub
825+ // for the same failure. Empty when the action was resolved, in which case
826+ // the other fields describe it.
827+ string error = 8;
828+}
829+
830+// UploadSummaryRequest carries the job summary of one step.
831+message UploadSummaryRequest {
832+ // JobId is the Job.job_id. It must be the job of the token.
833+ string job_id = 1;
834+ // StepNumber is the number of the step that wrote the summary (see
835+ // StepUpdate.number), from 1 to 1,000.
836+ int32 step_number = 2;
837+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
838+ // bytes). Empty removes the summary of the step.
839+ string markdown = 3;
840+}
841+
842+// UploadSummaryResponse is empty.
843+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,16 @@ 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.
233+ //
234+ // Fails with invalid_argument if a rule is broken (including the annotation
235+ // limits), with failed_precondition if a step goes back (a COMPLETED step
236+ // cannot change, a step cannot go from IN_PROGRESS to PENDING) and with
237+ // failed_precondition and a JobEnded detail if the job has ended.
198 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);238 rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse);
199 // AppendLog appends lines to the log of a job. Needs the job token.239 // AppendLog appends lines to the log of a job. Needs the job token.
200 //240 //
@@ -299,9 +339,53 @@ service RunnerService {
299 // ends are completed by the server as CI_CONCLUSION_CANCELLED (or SKIPPED when339 // 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).340 // they never started and the job did not end by cancellation).
301 //341 //
302- // Fails with invalid_argument if a rule is broken (including the output342+ // Annotations are applied as in UpdateJob, together with the conclusion.
303- // limits) and failed_precondition if a step goes back, as in UpdateJob.343+ // Summaries are not part of this call: a runner sends them with
344+ // UploadSummary before it.
345+ //
346+ // Fails with invalid_argument if a rule is broken (including the output and
347+ // annotation limits) and failed_precondition if a step goes back, as in
348+ // UpdateJob.
304 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);349 rpc CompleteJob(CompleteJobRequest) returns (CompleteJobResponse);
350+ // ResolveActions turns the "uses" of workflow and action steps into what the
351+ // runner needs to download the actions, as GitHub's action download info
352+ // does. Needs the job token; the job_id must be the one of the token. It
353+ // may be called as often as needed while the job runs (the runner calls it
354+ // once per level of composite actions, see the runner's depth limit of 9).
355+ // The runner then downloads each archive itself, from the sandbox, with the
356+ // token of the ResolvedAction when there is one.
357+ //
358+ // The response has one ResolvedAction per ActionRef, in the same order. A
359+ // reference that cannot be resolved (unknown repository, tag or branch, a
360+ // repository without access, a "uses" that GitHub itself would reject) does
361+ // not fail the call: its ResolvedAction has only ref and error, where error
362+ // is the message GitHub gives for the same failure, which the runner prints
363+ // as is. Only a failure of the call itself (credential, ended job, bad
364+ // request, server error) is an RPC error; the runner then fails the job.
365+ //
366+ // Resolution is stable for a run: the same ref resolves to the same sha for
367+ // every job and every call of one attempt of the run. A re-run attempt
368+ // resolves again.
369+ //
370+ // Fails with unauthenticated or permission_denied as the other job RPCs,
371+ // with failed_precondition and a JobEnded detail if the job has ended, and
372+ // with invalid_argument if there are more than 100 refs or if a "uses" is a
373+ // local action ("./path") or a Docker image ("docker://"), which the runner
374+ // handles without the server.
375+ rpc ResolveActions(ResolveActionsRequest) returns (ResolveActionsResponse);
376+ // UploadSummary stores the job summary of one step: the Markdown that the
377+ // step wrote to the file named by GITHUB_STEP_SUMMARY. Needs the job token.
378+ // The runner masks it before sending it, and sends it after the step ended
379+ // and before CompleteJob.
380+ //
381+ // It is idempotent: the summary of a step is replaced by each call, so a
382+ // retry changes nothing, and an empty markdown removes the summary of the
383+ // step. The Markdown is at most 1 MiB (1,048,576 bytes) and valid UTF-8;
384+ // clients set a message size limit above it.
385+ //
386+ // Fails with invalid_argument if a rule is broken (size, UTF-8, step number)
387+ // and with failed_precondition and a JobEnded detail if the job has ended.
388+ rpc UploadSummary(UploadSummaryRequest) returns (UploadSummaryResponse);
305 }389 }
306 390
307 // RegisterRunnerRequest describes the runner to register.391 // RegisterRunnerRequest describes the runner to register.
@@ -437,6 +521,18 @@ message Job {
437 // Ref is the full ref name that triggered the run, for example521 // Ref is the full ref name that triggered the run, for example
438 // "refs/heads/main" or "refs/tags/v1.0.0".522 // "refs/heads/main" or "refs/tags/v1.0.0".
439 string ref = 14;523 string ref = 14;
524+ // GithubToken is the job repository token, the "github.token" and
525+ // "secrets.GITHUB_TOKEN" of the job: "ermitegh_" and 43 base64url characters
526+ // (32 random bytes, no padding). Unlike job_token it is meant for the code of
527+ // the job: the runner gives it to the sandbox (actions/checkout clones with
528+ // it). It can only read the repository of the run (read-only, whatever
529+ // "permissions:" says), and is valid from the assignment until the job ends
530+ // (it is revoked then, on cancellation and when the job is lost). It is a
531+ // secret: the runner registers it in its masker before anything runs, and
532+ // neither the runner nor the server logs it. It is shown only in this
533+ // response, or in a repeat of the same poll_id; a new assignment of the same
534+ // job has a new one. Empty from servers without the feature "ci.actions".
535+ string github_token = 15;
440 }536 }
441 537
442 // UpdateJobRequest reports the steps of a running job.538 // UpdateJobRequest reports the steps of a running job.
@@ -449,6 +545,12 @@ message UpdateJobRequest {
449 // implicit "Set up job" is 1, the steps of the workflow follow in order, and545 // implicit "Set up job" is 1, the steps of the workflow follow in order, and
450 // the implicit "Complete job" is last.546 // the implicit "Complete job" is last.
451 repeated StepUpdate steps = 2;547 repeated StepUpdate steps = 2;
548+ // Annotations are the annotations of the steps that the call names: for
549+ // each step_number present, all the annotations of that step known so far,
550+ // not only the new ones (see the rules on UpdateJob). At most 10 per level
551+ // and per step; more is invalid_argument. The server ignores them without
552+ // the feature "ci.annotations".
553+ repeated Annotation annotations = 3;
452 }554 }
453 555
454 // StepUpdate is the state of one step as the runner knows it.556 // StepUpdate is the state of one step as the runner knows it.
@@ -472,6 +574,14 @@ message StepUpdate {
472 // CompletedAt is when the step ended, by the clock of the runner. Required574 // CompletedAt is when the step ended, by the clock of the runner. Required
473 // when state is COMPLETED.575 // when state is COMPLETED.
474 google.protobuf.Timestamp completed_at = 6;576 google.protobuf.Timestamp completed_at = 6;
577+ // Outcome is how the step ended before continue-on-error was applied, GitHub's
578+ // "steps.<id>.outcome", whereas conclusion is the result after it
579+ // ("steps.<id>.conclusion"). Same values as conclusion. They differ only for
580+ // a step with continue-on-error that failed: outcome FAILURE, conclusion
581+ // SUCCESS. Set by the runner when state is COMPLETED and UNSPECIFIED
582+ // otherwise; UNSPECIFIED in a COMPLETED step means the same as conclusion
583+ // (a runner that does not know the field).
584+ CiConclusion outcome = 7;
475 }585 }
476 586
477 // UpdateJobResponse is empty.587 // UpdateJobResponse is empty.
@@ -504,6 +614,11 @@ message CompleteJobRequest {
504 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,614 // Steps are the final steps, with the same meaning as UpdateJobRequest.steps,
505 // applied in the same atomic step as the conclusion.615 // applied in the same atomic step as the conclusion.
506 repeated StepUpdate steps = 5;616 repeated StepUpdate steps = 5;
617+ // Annotations are those of the steps that changed since the last call, with
618+ // the rules of UpdateJobRequest.annotations (all the annotations of each
619+ // step named). The server ignores them without the feature
620+ // "ci.annotations".
621+ repeated Annotation annotations = 6;
507 }622 }
508 623
509 // CompleteJobResponse is the stored result of a job.624 // CompleteJobResponse is the stored result of a job.
@@ -620,3 +735,109 @@ message CancelRequest {
620 // server.735 // server.
621 google.protobuf.Timestamp requested_at = 3;736 google.protobuf.Timestamp requested_at = 3;
622 }737 }
738+
739+// Annotation is a message attached to a step, and optionally to a place in a
740+// file of the repository, like an annotation of a GitHub check run. The runner
741+// produces them from the workflow commands ::notice, ::warning and ::error and
742+// from problem matchers, after masking.
743+//
744+// The runner sends at most 10 annotations of each level per step (the ones
745+// beyond only reach the log) and the server rejects more.
746+message Annotation {
747+ // Level is the severity. Required.
748+ AnnotationLevel level = 1;
749+ // Title is the optional title. Empty when not given.
750+ string title = 2;
751+ // Message is the text, at most 4,096 characters (the runner cuts longer
752+ // ones). Required, not empty.
753+ string message = 3;
754+ // File is the path the annotation is about, relative to the repository when
755+ // the runner can tell, else as given. Empty when the annotation is not about
756+ // a file.
757+ string file = 4;
758+ // StartLine is the first line, counted from 1. 0 when not given.
759+ int32 start_line = 5;
760+ // EndLine is the last line, counted from 1, not before start_line. 0 when
761+ // not given.
762+ int32 end_line = 6;
763+ // StartColumn is the first column, counted from 1. 0 when not given.
764+ int32 start_column = 7;
765+ // EndColumn is the last column, counted from 1. 0 when not given.
766+ int32 end_column = 8;
767+ // StepNumber is the number of the step that produced it (see
768+ // StepUpdate.number), from 1 to 1,000. An annotation of a step inside a
769+ // composite action belongs to the step of the workflow that uses the action.
770+ int32 step_number = 9;
771+}
772+
773+// ActionRef is an action to resolve.
774+message ActionRef {
775+ // Uses is the value of "uses" as written, after expression evaluation, for
776+ // example "actions/checkout@v4" or "owner/repo/path/to/action@ref". Required.
777+ string uses = 1;
778+}
779+
780+// ResolveActionsRequest lists the actions to resolve.
781+message ResolveActionsRequest {
782+ // JobId is the Job.job_id. It must be the job of the token.
783+ string job_id = 1;
784+ // Refs are the actions to resolve, at most 100. Duplicates are allowed and
785+ // answered one by one.
786+ repeated ActionRef refs = 2;
787+}
788+
789+// ResolveActionsResponse holds the resolution of each action.
790+message ResolveActionsResponse {
791+ // Actions has one entry per ActionRef of the request, in the same order.
792+ repeated ResolvedAction actions = 1;
793+}
794+
795+// ResolvedAction is where to download one action, or why it cannot be.
796+message ResolvedAction {
797+ // Ref is the ActionRef.uses of the request, unchanged.
798+ string ref = 1;
799+ // NameWithOwner is the repository of the action, "owner/repo", with the
800+ // case of the repository as the source gives it. Empty when error is set.
801+ string name_with_owner = 2;
802+ // Path is the sub-path of the action inside the repository, without leading
803+ // or trailing slash: "path/to/action" for "owner/repo/path/to/action@ref".
804+ // Empty for an action at the root of the repository.
805+ string path = 3;
806+ // ResolvedSha is the full id of the commit the ref points to, 40 lowercase
807+ // hexadecimal characters for SHA-1 (the commit that an annotated tag points
808+ // to, not the tag object). Empty when error is set.
809+ string resolved_sha = 4;
810+ // TarballUrl is where to download the archive of the repository at
811+ // resolved_sha, a gzip-compressed tar with one top-level directory. The
812+ // runner downloads it from the sandbox. Empty when error is set.
813+ string tarball_url = 5;
814+ // Token authenticates the download: the runner sends it as "Authorization:
815+ // Basic" with the user "x-access-token". Empty for ACTION_SOURCE_GITHUB.
816+ // For ACTION_SOURCE_ERMITE it is a read token for that one repository,
817+ // valid until the job ends, so a job can use an action of another private
818+ // repository of the server that its own repository token cannot read. It is
819+ // a secret: the runner masks it, and neither the runner nor the server logs
820+ // it.
821+ string token = 6;
822+ // Source is where the action was found. UNSPECIFIED when error is set.
823+ ActionSource source = 7;
824+ // Error is why the reference could not be resolved, in the words of GitHub
825+ // for the same failure. Empty when the action was resolved, in which case
826+ // the other fields describe it.
827+ string error = 8;
828+}
829+
830+// UploadSummaryRequest carries the job summary of one step.
831+message UploadSummaryRequest {
832+ // JobId is the Job.job_id. It must be the job of the token.
833+ string job_id = 1;
834+ // StepNumber is the number of the step that wrote the summary (see
835+ // StepUpdate.number), from 1 to 1,000.
836+ int32 step_number = 2;
837+ // Markdown is the summary, masked, valid UTF-8, at most 1 MiB (1,048,576
838+ // bytes). Empty removes the summary of the step.
839+ string markdown = 3;
840+}
841+
842+// UploadSummaryResponse is empty.
843+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