detached 9d26b26

feat(proto): artifacts v4 for runners (#12)

commit
9d26b26e5e6f2c66781a446e07994ba46b35fa23
author
brice · · 2026-10-16 07:33 UTC
committer
bnema · · 2026-10-16 07:33 UTC
parent
89aa722
signature
SSH UnverifiedSHA256:VOCA5lYARHcbKDZ7GhTV45VmcjWnJ6ZQIBazj17LivA The key is unknown
7 files · +2446 -4
M README.md +4 -2
@@ -2,7 +2,7 @@
22
33 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.
44
5-Status: early development. The contract defines twelve services (below); the server that implements them is being built.
5+Status: early development. The contract defines fourteen services (below); the server that implements them is being built.
66
77 ```go
88 import "bnema.dev/ermite-api/gen/ermite"
@@ -27,13 +27,15 @@ Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
2727 | `SecretService` | `SetSecret`, `ListSecrets` (names only, never values), `DeleteSecret`; scopes instance, repository and environment |
2828 | `VariableService` | `SetVariable`, `GetVariable`, `ListVariables`, `DeleteVariable`; same scopes |
2929 | `EnvironmentService` | `CreateEnvironment`, `ListEnvironments`, `DeleteEnvironment` |
30+| `JobArtifactService` | `CreateJobArtifact`, `UploadJobArtifactBlock` (client stream), `CommitJobArtifact`, `FinalizeJobArtifact`, `ListJobArtifacts`, `DownloadJobArtifact` (streamed, resumable), `DeleteJobArtifact`; artifacts v4 for CI runners, scoped to the run of the job token |
31+| `ArtifactService` | `ListArtifacts`, `DownloadArtifact` (streamed, resumable), `DeleteArtifact`; artifacts of a run for people |
3032 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |
3133
3234 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
3335
3436 ## Layout
3537
36-- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `merge_request`, `token`, `session`, `event`, `server`, `runner`, `run`, `ci_settings`) plus shared `types`. Checked by `buf lint` and `buf breaking`.
38+- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `merge_request`, `token`, `session`, `event`, `server`, `runner`, `run`, `ci_settings`, `artifact`) plus shared `types`. Checked by `buf lint` and `buf breaking`.
3739 - `gen/ermite/`: generated Go messages. `gen/ermite/ermiteconnect/`: generated Connect clients and handlers. Committed, never edited by hand.
3840
3941 ## Generate
@@ -2,7 +2,7 @@
2 2
3 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.3 The public API contract of [ermite](https://git.bnema.dev/bnema/ermite), a single-user Git forge: protobuf definitions for its ConnectRPC services and the Go code generated from them.
4 4
5-Status: early development. The contract defines twelve services (below); the server that implements them is being built.5+Status: early development. The contract defines fourteen services (below); the server that implements them is being built.
6 6
7 ```go7 ```go
8 import "bnema.dev/ermite-api/gen/ermite"8 import "bnema.dev/ermite-api/gen/ermite"
@@ -27,13 +27,15 @@ Handlers are mounted under `/-/api/` by the server. Errors are Connect codes.
27 | `SecretService` | `SetSecret`, `ListSecrets` (names only, never values), `DeleteSecret`; scopes instance, repository and environment |27 | `SecretService` | `SetSecret`, `ListSecrets` (names only, never values), `DeleteSecret`; scopes instance, repository and environment |
28 | `VariableService` | `SetVariable`, `GetVariable`, `ListVariables`, `DeleteVariable`; same scopes |28 | `VariableService` | `SetVariable`, `GetVariable`, `ListVariables`, `DeleteVariable`; same scopes |
29 | `EnvironmentService` | `CreateEnvironment`, `ListEnvironments`, `DeleteEnvironment` |29 | `EnvironmentService` | `CreateEnvironment`, `ListEnvironments`, `DeleteEnvironment` |
30+| `JobArtifactService` | `CreateJobArtifact`, `UploadJobArtifactBlock` (client stream), `CommitJobArtifact`, `FinalizeJobArtifact`, `ListJobArtifacts`, `DownloadJobArtifact` (streamed, resumable), `DeleteJobArtifact`; artifacts v4 for CI runners, scoped to the run of the job token |
31+| `ArtifactService` | `ListArtifacts`, `DownloadArtifact` (streamed, resumable), `DeleteArtifact`; artifacts of a run for people |
30 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |32 | `ServerService` | `GetVersion` (server version and feature list), `GetSigningKey` (commit signing key) |
31 33
32 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.34 Tokens carry scopes only; presets such as `cli` or `agent` are a client concern.
33 35
34 ## Layout36 ## Layout
35 37
36-- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `merge_request`, `token`, `session`, `event`, `server`, `runner`, `run`, `ci_settings`) plus shared `types`. Checked by `buf lint` and `buf breaking`.38+- `proto/ermite/`: `.proto` files of the `ermite` package, one per service (`repo`, `git`, `merge_request`, `token`, `session`, `event`, `server`, `runner`, `run`, `ci_settings`, `artifact`) plus shared `types`. Checked by `buf lint` and `buf breaking`.
37 - `gen/ermite/`: generated Go messages. `gen/ermite/ermiteconnect/`: generated Connect clients and handlers. Committed, never edited by hand.39 - `gen/ermite/`: generated Go messages. `gen/ermite/ermiteconnect/`: generated Connect clients and handlers. Committed, never edited by hand.
38 40
39 ## Generate41 ## Generate
A gen/ermite/artifact.pb.go +1548 -0
@@ -0,0 +1,1548 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-go. DO NOT EDIT.
4+// versions:
5+// protoc-gen-go v1.36.12
6+// protoc (unknown)
7+// source: ermite/artifact.proto
8+
9+package ermite
10+
11+import (
12+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
13+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
14+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
15+ reflect "reflect"
16+ sync "sync"
17+ unsafe "unsafe"
18+)
19+
20+const (
21+ // Verify that this generated code is sufficiently up-to-date.
22+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
23+ // Verify that runtime/protoimpl is sufficiently up-to-date.
24+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
25+)
26+
27+// Artifact is a file that a job of a run uploaded with actions/upload-artifact
28+// (artifacts v4): in most cases a zip archive, or a single file uploaded as is
29+// ("archive: false"). It belongs to a run, not to one attempt: every job of the
30+// run, in any attempt, sees the artifacts of the run. Only finalized artifacts
31+// are described; an upload in progress is invisible.
32+type Artifact struct {
33+ state protoimpl.MessageState `protogen:"open.v1"`
34+ // Id identifies the artifact on the server: unique across repositories and
35+ // runs, never reused, and higher for a later artifact. It is GitHub's
36+ // "artifact id" (databaseId), the id of the REST API.
37+ Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
38+ // Repo is the name of the repository of the run.
39+ Repo string `protobuf:"bytes,2,opt,name=repo,proto3" json:"repo,omitempty"`
40+ // RunId is the run the artifact belongs to.
41+ RunId int64 `protobuf:"varint,3,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
42+ // Attempt is the attempt of the run whose job uploaded it.
43+ Attempt int32 `protobuf:"varint,4,opt,name=attempt,proto3" json:"attempt,omitempty"`
44+ // JobId is the Job.job_id of the job that uploaded it.
45+ JobId string `protobuf:"bytes,5,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
46+ // Name is the name of the artifact, unique among the artifacts of the run:
47+ // 1 to 256 characters of valid UTF-8, without control characters, '"', ':',
48+ // '<', '>', '|', '*', '?', '\' or '/' (the characters @actions/artifact
49+ // refuses).
50+ Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
51+ // Size is the number of bytes of the content.
52+ Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"`
53+ // Digest is the SHA-256 of the content, "sha256:" and 64 lowercase
54+ // hexadecimal characters, as GitHub gives it.
55+ Digest string `protobuf:"bytes,8,opt,name=digest,proto3" json:"digest,omitempty"`
56+ // MediaType is the media type of the content: "application/zip" for an
57+ // archive, the type the uploader gave for a file uploaded as is.
58+ MediaType string `protobuf:"bytes,9,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"`
59+ // CreatedAt is when the upload began.
60+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
61+ // ExpiresAt is when the server deletes the artifact (see
62+ // CreateJobArtifactRequest.expires_at).
63+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
64+ unknownFields protoimpl.UnknownFields
65+ sizeCache protoimpl.SizeCache
66+}
67+
68+func (x *Artifact) Reset() {
69+ *x = Artifact{}
70+ mi := &file_ermite_artifact_proto_msgTypes[0]
71+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
72+ ms.StoreMessageInfo(mi)
73+}
74+
75+func (x *Artifact) String() string {
76+ return protoimpl.X.MessageStringOf(x)
77+}
78+
79+func (*Artifact) ProtoMessage() {}
80+
81+func (x *Artifact) ProtoReflect() protoreflect.Message {
82+ mi := &file_ermite_artifact_proto_msgTypes[0]
83+ if x != nil {
84+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
85+ if ms.LoadMessageInfo() == nil {
86+ ms.StoreMessageInfo(mi)
87+ }
88+ return ms
89+ }
90+ return mi.MessageOf(x)
91+}
92+
93+// Deprecated: Use Artifact.ProtoReflect.Descriptor instead.
94+func (*Artifact) Descriptor() ([]byte, []int) {
95+ return file_ermite_artifact_proto_rawDescGZIP(), []int{0}
96+}
97+
98+func (x *Artifact) GetId() int64 {
99+ if x != nil {
100+ return x.Id
101+ }
102+ return 0
103+}
104+
105+func (x *Artifact) GetRepo() string {
106+ if x != nil {
107+ return x.Repo
108+ }
109+ return ""
110+}
111+
112+func (x *Artifact) GetRunId() int64 {
113+ if x != nil {
114+ return x.RunId
115+ }
116+ return 0
117+}
118+
119+func (x *Artifact) GetAttempt() int32 {
120+ if x != nil {
121+ return x.Attempt
122+ }
123+ return 0
124+}
125+
126+func (x *Artifact) GetJobId() string {
127+ if x != nil {
128+ return x.JobId
129+ }
130+ return ""
131+}
132+
133+func (x *Artifact) GetName() string {
134+ if x != nil {
135+ return x.Name
136+ }
137+ return ""
138+}
139+
140+func (x *Artifact) GetSize() int64 {
141+ if x != nil {
142+ return x.Size
143+ }
144+ return 0
145+}
146+
147+func (x *Artifact) GetDigest() string {
148+ if x != nil {
149+ return x.Digest
150+ }
151+ return ""
152+}
153+
154+func (x *Artifact) GetMediaType() string {
155+ if x != nil {
156+ return x.MediaType
157+ }
158+ return ""
159+}
160+
161+func (x *Artifact) GetCreatedAt() *timestamppb.Timestamp {
162+ if x != nil {
163+ return x.CreatedAt
164+ }
165+ return nil
166+}
167+
168+func (x *Artifact) GetExpiresAt() *timestamppb.Timestamp {
169+ if x != nil {
170+ return x.ExpiresAt
171+ }
172+ return nil
173+}
174+
175+// CreateJobArtifactRequest begins an upload.
176+type CreateJobArtifactRequest struct {
177+ state protoimpl.MessageState `protogen:"open.v1"`
178+ // JobId is the Job.job_id. It must be the job of the token.
179+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
180+ // Name is the name of the artifact, see Artifact.name.
181+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
182+ // MediaType is the media type of a file uploaded as is (the toolkit's
183+ // mime_type), at most 255 characters. Empty means "application/zip".
184+ MediaType string `protobuf:"bytes,3,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"`
185+ // ExpiresAt is when the artifact should be deleted (the toolkit's
186+ // expires_at, from "retention-days"). Unset means the default retention of
187+ // the server. The server keeps it between one day from now and its longest
188+ // retention, and returns the time it kept.
189+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
190+ unknownFields protoimpl.UnknownFields
191+ sizeCache protoimpl.SizeCache
192+}
193+
194+func (x *CreateJobArtifactRequest) Reset() {
195+ *x = CreateJobArtifactRequest{}
196+ mi := &file_ermite_artifact_proto_msgTypes[1]
197+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
198+ ms.StoreMessageInfo(mi)
199+}
200+
201+func (x *CreateJobArtifactRequest) String() string {
202+ return protoimpl.X.MessageStringOf(x)
203+}
204+
205+func (*CreateJobArtifactRequest) ProtoMessage() {}
206+
207+func (x *CreateJobArtifactRequest) ProtoReflect() protoreflect.Message {
208+ mi := &file_ermite_artifact_proto_msgTypes[1]
209+ if x != nil {
210+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
211+ if ms.LoadMessageInfo() == nil {
212+ ms.StoreMessageInfo(mi)
213+ }
214+ return ms
215+ }
216+ return mi.MessageOf(x)
217+}
218+
219+// Deprecated: Use CreateJobArtifactRequest.ProtoReflect.Descriptor instead.
220+func (*CreateJobArtifactRequest) Descriptor() ([]byte, []int) {
221+ return file_ermite_artifact_proto_rawDescGZIP(), []int{1}
222+}
223+
224+func (x *CreateJobArtifactRequest) GetJobId() string {
225+ if x != nil {
226+ return x.JobId
227+ }
228+ return ""
229+}
230+
231+func (x *CreateJobArtifactRequest) GetName() string {
232+ if x != nil {
233+ return x.Name
234+ }
235+ return ""
236+}
237+
238+func (x *CreateJobArtifactRequest) GetMediaType() string {
239+ if x != nil {
240+ return x.MediaType
241+ }
242+ return ""
243+}
244+
245+func (x *CreateJobArtifactRequest) GetExpiresAt() *timestamppb.Timestamp {
246+ if x != nil {
247+ return x.ExpiresAt
248+ }
249+ return nil
250+}
251+
252+// CreateJobArtifactResponse identifies the pending artifact.
253+type CreateJobArtifactResponse struct {
254+ state protoimpl.MessageState `protogen:"open.v1"`
255+ // ArtifactId is the id the artifact will have once finalized (Artifact.id).
256+ ArtifactId int64 `protobuf:"varint,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
257+ // ExpiresAt is the expiry the server kept.
258+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
259+ unknownFields protoimpl.UnknownFields
260+ sizeCache protoimpl.SizeCache
261+}
262+
263+func (x *CreateJobArtifactResponse) Reset() {
264+ *x = CreateJobArtifactResponse{}
265+ mi := &file_ermite_artifact_proto_msgTypes[2]
266+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
267+ ms.StoreMessageInfo(mi)
268+}
269+
270+func (x *CreateJobArtifactResponse) String() string {
271+ return protoimpl.X.MessageStringOf(x)
272+}
273+
274+func (*CreateJobArtifactResponse) ProtoMessage() {}
275+
276+func (x *CreateJobArtifactResponse) ProtoReflect() protoreflect.Message {
277+ mi := &file_ermite_artifact_proto_msgTypes[2]
278+ if x != nil {
279+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
280+ if ms.LoadMessageInfo() == nil {
281+ ms.StoreMessageInfo(mi)
282+ }
283+ return ms
284+ }
285+ return mi.MessageOf(x)
286+}
287+
288+// Deprecated: Use CreateJobArtifactResponse.ProtoReflect.Descriptor instead.
289+func (*CreateJobArtifactResponse) Descriptor() ([]byte, []int) {
290+ return file_ermite_artifact_proto_rawDescGZIP(), []int{2}
291+}
292+
293+func (x *CreateJobArtifactResponse) GetArtifactId() int64 {
294+ if x != nil {
295+ return x.ArtifactId
296+ }
297+ return 0
298+}
299+
300+func (x *CreateJobArtifactResponse) GetExpiresAt() *timestamppb.Timestamp {
301+ if x != nil {
302+ return x.ExpiresAt
303+ }
304+ return nil
305+}
306+
307+// UploadJobArtifactBlockRequest is one message of the stream of a block.
308+type UploadJobArtifactBlockRequest struct {
309+ state protoimpl.MessageState `protogen:"open.v1"`
310+ // JobId is the Job.job_id, in the first message only. It must be the job of
311+ // the token.
312+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
313+ // ArtifactId is the CreateJobArtifactResponse.artifact_id, in the first
314+ // message only.
315+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
316+ // BlockId identifies the block within the artifact: 1 to 64 bytes (Azure's
317+ // block id, decoded from base64), in the first message only.
318+ BlockId []byte `protobuf:"bytes,3,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
319+ // Data is the next part of the block, at most 1 MiB (1,048,576 bytes). Any
320+ // message may have none.
321+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
322+ unknownFields protoimpl.UnknownFields
323+ sizeCache protoimpl.SizeCache
324+}
325+
326+func (x *UploadJobArtifactBlockRequest) Reset() {
327+ *x = UploadJobArtifactBlockRequest{}
328+ mi := &file_ermite_artifact_proto_msgTypes[3]
329+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
330+ ms.StoreMessageInfo(mi)
331+}
332+
333+func (x *UploadJobArtifactBlockRequest) String() string {
334+ return protoimpl.X.MessageStringOf(x)
335+}
336+
337+func (*UploadJobArtifactBlockRequest) ProtoMessage() {}
338+
339+func (x *UploadJobArtifactBlockRequest) ProtoReflect() protoreflect.Message {
340+ mi := &file_ermite_artifact_proto_msgTypes[3]
341+ if x != nil {
342+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
343+ if ms.LoadMessageInfo() == nil {
344+ ms.StoreMessageInfo(mi)
345+ }
346+ return ms
347+ }
348+ return mi.MessageOf(x)
349+}
350+
351+// Deprecated: Use UploadJobArtifactBlockRequest.ProtoReflect.Descriptor instead.
352+func (*UploadJobArtifactBlockRequest) Descriptor() ([]byte, []int) {
353+ return file_ermite_artifact_proto_rawDescGZIP(), []int{3}
354+}
355+
356+func (x *UploadJobArtifactBlockRequest) GetJobId() string {
357+ if x != nil {
358+ return x.JobId
359+ }
360+ return ""
361+}
362+
363+func (x *UploadJobArtifactBlockRequest) GetArtifactId() int64 {
364+ if x != nil {
365+ return x.ArtifactId
366+ }
367+ return 0
368+}
369+
370+func (x *UploadJobArtifactBlockRequest) GetBlockId() []byte {
371+ if x != nil {
372+ return x.BlockId
373+ }
374+ return nil
375+}
376+
377+func (x *UploadJobArtifactBlockRequest) GetData() []byte {
378+ if x != nil {
379+ return x.Data
380+ }
381+ return nil
382+}
383+
384+// UploadJobArtifactBlockResponse confirms a stored block.
385+type UploadJobArtifactBlockResponse struct {
386+ state protoimpl.MessageState `protogen:"open.v1"`
387+ // Size is the number of bytes of the block as stored.
388+ Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
389+ unknownFields protoimpl.UnknownFields
390+ sizeCache protoimpl.SizeCache
391+}
392+
393+func (x *UploadJobArtifactBlockResponse) Reset() {
394+ *x = UploadJobArtifactBlockResponse{}
395+ mi := &file_ermite_artifact_proto_msgTypes[4]
396+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
397+ ms.StoreMessageInfo(mi)
398+}
399+
400+func (x *UploadJobArtifactBlockResponse) String() string {
401+ return protoimpl.X.MessageStringOf(x)
402+}
403+
404+func (*UploadJobArtifactBlockResponse) ProtoMessage() {}
405+
406+func (x *UploadJobArtifactBlockResponse) ProtoReflect() protoreflect.Message {
407+ mi := &file_ermite_artifact_proto_msgTypes[4]
408+ if x != nil {
409+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
410+ if ms.LoadMessageInfo() == nil {
411+ ms.StoreMessageInfo(mi)
412+ }
413+ return ms
414+ }
415+ return mi.MessageOf(x)
416+}
417+
418+// Deprecated: Use UploadJobArtifactBlockResponse.ProtoReflect.Descriptor instead.
419+func (*UploadJobArtifactBlockResponse) Descriptor() ([]byte, []int) {
420+ return file_ermite_artifact_proto_rawDescGZIP(), []int{4}
421+}
422+
423+func (x *UploadJobArtifactBlockResponse) GetSize() int64 {
424+ if x != nil {
425+ return x.Size
426+ }
427+ return 0
428+}
429+
430+// CommitJobArtifactRequest sets the content of a pending artifact.
431+type CommitJobArtifactRequest struct {
432+ state protoimpl.MessageState `protogen:"open.v1"`
433+ // JobId is the Job.job_id. It must be the job of the token.
434+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
435+ // ArtifactId is the CreateJobArtifactResponse.artifact_id.
436+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
437+ // BlockIds are the blocks of the content, in order, each one as given to
438+ // UploadJobArtifactBlock. At most 50,000; the same id may appear more than
439+ // once.
440+ BlockIds [][]byte `protobuf:"bytes,3,rep,name=block_ids,json=blockIds,proto3" json:"block_ids,omitempty"`
441+ unknownFields protoimpl.UnknownFields
442+ sizeCache protoimpl.SizeCache
443+}
444+
445+func (x *CommitJobArtifactRequest) Reset() {
446+ *x = CommitJobArtifactRequest{}
447+ mi := &file_ermite_artifact_proto_msgTypes[5]
448+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
449+ ms.StoreMessageInfo(mi)
450+}
451+
452+func (x *CommitJobArtifactRequest) String() string {
453+ return protoimpl.X.MessageStringOf(x)
454+}
455+
456+func (*CommitJobArtifactRequest) ProtoMessage() {}
457+
458+func (x *CommitJobArtifactRequest) ProtoReflect() protoreflect.Message {
459+ mi := &file_ermite_artifact_proto_msgTypes[5]
460+ if x != nil {
461+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
462+ if ms.LoadMessageInfo() == nil {
463+ ms.StoreMessageInfo(mi)
464+ }
465+ return ms
466+ }
467+ return mi.MessageOf(x)
468+}
469+
470+// Deprecated: Use CommitJobArtifactRequest.ProtoReflect.Descriptor instead.
471+func (*CommitJobArtifactRequest) Descriptor() ([]byte, []int) {
472+ return file_ermite_artifact_proto_rawDescGZIP(), []int{5}
473+}
474+
475+func (x *CommitJobArtifactRequest) GetJobId() string {
476+ if x != nil {
477+ return x.JobId
478+ }
479+ return ""
480+}
481+
482+func (x *CommitJobArtifactRequest) GetArtifactId() int64 {
483+ if x != nil {
484+ return x.ArtifactId
485+ }
486+ return 0
487+}
488+
489+func (x *CommitJobArtifactRequest) GetBlockIds() [][]byte {
490+ if x != nil {
491+ return x.BlockIds
492+ }
493+ return nil
494+}
495+
496+// CommitJobArtifactResponse describes the committed content.
497+type CommitJobArtifactResponse struct {
498+ state protoimpl.MessageState `protogen:"open.v1"`
499+ // Size is the number of bytes of the content.
500+ Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
501+ // Digest is the SHA-256 of the content, see Artifact.digest.
502+ Digest string `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"`
503+ unknownFields protoimpl.UnknownFields
504+ sizeCache protoimpl.SizeCache
505+}
506+
507+func (x *CommitJobArtifactResponse) Reset() {
508+ *x = CommitJobArtifactResponse{}
509+ mi := &file_ermite_artifact_proto_msgTypes[6]
510+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
511+ ms.StoreMessageInfo(mi)
512+}
513+
514+func (x *CommitJobArtifactResponse) String() string {
515+ return protoimpl.X.MessageStringOf(x)
516+}
517+
518+func (*CommitJobArtifactResponse) ProtoMessage() {}
519+
520+func (x *CommitJobArtifactResponse) ProtoReflect() protoreflect.Message {
521+ mi := &file_ermite_artifact_proto_msgTypes[6]
522+ if x != nil {
523+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
524+ if ms.LoadMessageInfo() == nil {
525+ ms.StoreMessageInfo(mi)
526+ }
527+ return ms
528+ }
529+ return mi.MessageOf(x)
530+}
531+
532+// Deprecated: Use CommitJobArtifactResponse.ProtoReflect.Descriptor instead.
533+func (*CommitJobArtifactResponse) Descriptor() ([]byte, []int) {
534+ return file_ermite_artifact_proto_rawDescGZIP(), []int{6}
535+}
536+
537+func (x *CommitJobArtifactResponse) GetSize() int64 {
538+ if x != nil {
539+ return x.Size
540+ }
541+ return 0
542+}
543+
544+func (x *CommitJobArtifactResponse) GetDigest() string {
545+ if x != nil {
546+ return x.Digest
547+ }
548+ return ""
549+}
550+
551+// FinalizeJobArtifactRequest ends an upload.
552+type FinalizeJobArtifactRequest struct {
553+ state protoimpl.MessageState `protogen:"open.v1"`
554+ // JobId is the Job.job_id. It must be the job of the token.
555+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
556+ // Name is the name given to CreateJobArtifact. The toolkit finalizes by name.
557+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
558+ // Size is the size the uploader counted. Informational: the server keeps the
559+ // size of the content it stored, and only logs a difference.
560+ Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
561+ // Digest is the digest the uploader computed ("sha256:<hex>"), or empty.
562+ // When set it must be the digest of the content.
563+ Digest string `protobuf:"bytes,4,opt,name=digest,proto3" json:"digest,omitempty"`
564+ unknownFields protoimpl.UnknownFields
565+ sizeCache protoimpl.SizeCache
566+}
567+
568+func (x *FinalizeJobArtifactRequest) Reset() {
569+ *x = FinalizeJobArtifactRequest{}
570+ mi := &file_ermite_artifact_proto_msgTypes[7]
571+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
572+ ms.StoreMessageInfo(mi)
573+}
574+
575+func (x *FinalizeJobArtifactRequest) String() string {
576+ return protoimpl.X.MessageStringOf(x)
577+}
578+
579+func (*FinalizeJobArtifactRequest) ProtoMessage() {}
580+
581+func (x *FinalizeJobArtifactRequest) ProtoReflect() protoreflect.Message {
582+ mi := &file_ermite_artifact_proto_msgTypes[7]
583+ if x != nil {
584+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
585+ if ms.LoadMessageInfo() == nil {
586+ ms.StoreMessageInfo(mi)
587+ }
588+ return ms
589+ }
590+ return mi.MessageOf(x)
591+}
592+
593+// Deprecated: Use FinalizeJobArtifactRequest.ProtoReflect.Descriptor instead.
594+func (*FinalizeJobArtifactRequest) Descriptor() ([]byte, []int) {
595+ return file_ermite_artifact_proto_rawDescGZIP(), []int{7}
596+}
597+
598+func (x *FinalizeJobArtifactRequest) GetJobId() string {
599+ if x != nil {
600+ return x.JobId
601+ }
602+ return ""
603+}
604+
605+func (x *FinalizeJobArtifactRequest) GetName() string {
606+ if x != nil {
607+ return x.Name
608+ }
609+ return ""
610+}
611+
612+func (x *FinalizeJobArtifactRequest) GetSize() int64 {
613+ if x != nil {
614+ return x.Size
615+ }
616+ return 0
617+}
618+
619+func (x *FinalizeJobArtifactRequest) GetDigest() string {
620+ if x != nil {
621+ return x.Digest
622+ }
623+ return ""
624+}
625+
626+// FinalizeJobArtifactResponse describes the artifact now visible.
627+type FinalizeJobArtifactResponse struct {
628+ state protoimpl.MessageState `protogen:"open.v1"`
629+ // Artifact is the finalized artifact.
630+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
631+ unknownFields protoimpl.UnknownFields
632+ sizeCache protoimpl.SizeCache
633+}
634+
635+func (x *FinalizeJobArtifactResponse) Reset() {
636+ *x = FinalizeJobArtifactResponse{}
637+ mi := &file_ermite_artifact_proto_msgTypes[8]
638+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
639+ ms.StoreMessageInfo(mi)
640+}
641+
642+func (x *FinalizeJobArtifactResponse) String() string {
643+ return protoimpl.X.MessageStringOf(x)
644+}
645+
646+func (*FinalizeJobArtifactResponse) ProtoMessage() {}
647+
648+func (x *FinalizeJobArtifactResponse) ProtoReflect() protoreflect.Message {
649+ mi := &file_ermite_artifact_proto_msgTypes[8]
650+ if x != nil {
651+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
652+ if ms.LoadMessageInfo() == nil {
653+ ms.StoreMessageInfo(mi)
654+ }
655+ return ms
656+ }
657+ return mi.MessageOf(x)
658+}
659+
660+// Deprecated: Use FinalizeJobArtifactResponse.ProtoReflect.Descriptor instead.
661+func (*FinalizeJobArtifactResponse) Descriptor() ([]byte, []int) {
662+ return file_ermite_artifact_proto_rawDescGZIP(), []int{8}
663+}
664+
665+func (x *FinalizeJobArtifactResponse) GetArtifact() *Artifact {
666+ if x != nil {
667+ return x.Artifact
668+ }
669+ return nil
670+}
671+
672+// ListJobArtifactsRequest selects artifacts of the job's run.
673+type ListJobArtifactsRequest struct {
674+ state protoimpl.MessageState `protogen:"open.v1"`
675+ // JobId is the Job.job_id. It must be the job of the token.
676+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
677+ // Name keeps only the artifact of that name. Empty means every name.
678+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
679+ // ArtifactId keeps only the artifact of that id. 0 means every id.
680+ ArtifactId int64 `protobuf:"varint,3,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
681+ unknownFields protoimpl.UnknownFields
682+ sizeCache protoimpl.SizeCache
683+}
684+
685+func (x *ListJobArtifactsRequest) Reset() {
686+ *x = ListJobArtifactsRequest{}
687+ mi := &file_ermite_artifact_proto_msgTypes[9]
688+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
689+ ms.StoreMessageInfo(mi)
690+}
691+
692+func (x *ListJobArtifactsRequest) String() string {
693+ return protoimpl.X.MessageStringOf(x)
694+}
695+
696+func (*ListJobArtifactsRequest) ProtoMessage() {}
697+
698+func (x *ListJobArtifactsRequest) ProtoReflect() protoreflect.Message {
699+ mi := &file_ermite_artifact_proto_msgTypes[9]
700+ if x != nil {
701+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
702+ if ms.LoadMessageInfo() == nil {
703+ ms.StoreMessageInfo(mi)
704+ }
705+ return ms
706+ }
707+ return mi.MessageOf(x)
708+}
709+
710+// Deprecated: Use ListJobArtifactsRequest.ProtoReflect.Descriptor instead.
711+func (*ListJobArtifactsRequest) Descriptor() ([]byte, []int) {
712+ return file_ermite_artifact_proto_rawDescGZIP(), []int{9}
713+}
714+
715+func (x *ListJobArtifactsRequest) GetJobId() string {
716+ if x != nil {
717+ return x.JobId
718+ }
719+ return ""
720+}
721+
722+func (x *ListJobArtifactsRequest) GetName() string {
723+ if x != nil {
724+ return x.Name
725+ }
726+ return ""
727+}
728+
729+func (x *ListJobArtifactsRequest) GetArtifactId() int64 {
730+ if x != nil {
731+ return x.ArtifactId
732+ }
733+ return 0
734+}
735+
736+// ListJobArtifactsResponse lists artifacts of the job's run.
737+type ListJobArtifactsResponse struct {
738+ state protoimpl.MessageState `protogen:"open.v1"`
739+ // Artifacts are the artifacts, by id.
740+ Artifacts []*Artifact `protobuf:"bytes,1,rep,name=artifacts,proto3" json:"artifacts,omitempty"`
741+ unknownFields protoimpl.UnknownFields
742+ sizeCache protoimpl.SizeCache
743+}
744+
745+func (x *ListJobArtifactsResponse) Reset() {
746+ *x = ListJobArtifactsResponse{}
747+ mi := &file_ermite_artifact_proto_msgTypes[10]
748+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
749+ ms.StoreMessageInfo(mi)
750+}
751+
752+func (x *ListJobArtifactsResponse) String() string {
753+ return protoimpl.X.MessageStringOf(x)
754+}
755+
756+func (*ListJobArtifactsResponse) ProtoMessage() {}
757+
758+func (x *ListJobArtifactsResponse) ProtoReflect() protoreflect.Message {
759+ mi := &file_ermite_artifact_proto_msgTypes[10]
760+ if x != nil {
761+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
762+ if ms.LoadMessageInfo() == nil {
763+ ms.StoreMessageInfo(mi)
764+ }
765+ return ms
766+ }
767+ return mi.MessageOf(x)
768+}
769+
770+// Deprecated: Use ListJobArtifactsResponse.ProtoReflect.Descriptor instead.
771+func (*ListJobArtifactsResponse) Descriptor() ([]byte, []int) {
772+ return file_ermite_artifact_proto_rawDescGZIP(), []int{10}
773+}
774+
775+func (x *ListJobArtifactsResponse) GetArtifacts() []*Artifact {
776+ if x != nil {
777+ return x.Artifacts
778+ }
779+ return nil
780+}
781+
782+// DownloadJobArtifactRequest selects the content of an artifact.
783+type DownloadJobArtifactRequest struct {
784+ state protoimpl.MessageState `protogen:"open.v1"`
785+ // JobId is the Job.job_id. It must be the job of the token.
786+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
787+ // ArtifactId is the Artifact.id of an artifact of the job's run.
788+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
789+ // Offset is the first byte to send, from 0 to the size of the artifact.
790+ Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
791+ unknownFields protoimpl.UnknownFields
792+ sizeCache protoimpl.SizeCache
793+}
794+
795+func (x *DownloadJobArtifactRequest) Reset() {
796+ *x = DownloadJobArtifactRequest{}
797+ mi := &file_ermite_artifact_proto_msgTypes[11]
798+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
799+ ms.StoreMessageInfo(mi)
800+}
801+
802+func (x *DownloadJobArtifactRequest) String() string {
803+ return protoimpl.X.MessageStringOf(x)
804+}
805+
806+func (*DownloadJobArtifactRequest) ProtoMessage() {}
807+
808+func (x *DownloadJobArtifactRequest) ProtoReflect() protoreflect.Message {
809+ mi := &file_ermite_artifact_proto_msgTypes[11]
810+ if x != nil {
811+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
812+ if ms.LoadMessageInfo() == nil {
813+ ms.StoreMessageInfo(mi)
814+ }
815+ return ms
816+ }
817+ return mi.MessageOf(x)
818+}
819+
820+// Deprecated: Use DownloadJobArtifactRequest.ProtoReflect.Descriptor instead.
821+func (*DownloadJobArtifactRequest) Descriptor() ([]byte, []int) {
822+ return file_ermite_artifact_proto_rawDescGZIP(), []int{11}
823+}
824+
825+func (x *DownloadJobArtifactRequest) GetJobId() string {
826+ if x != nil {
827+ return x.JobId
828+ }
829+ return ""
830+}
831+
832+func (x *DownloadJobArtifactRequest) GetArtifactId() int64 {
833+ if x != nil {
834+ return x.ArtifactId
835+ }
836+ return 0
837+}
838+
839+func (x *DownloadJobArtifactRequest) GetOffset() int64 {
840+ if x != nil {
841+ return x.Offset
842+ }
843+ return 0
844+}
845+
846+// DownloadJobArtifactResponse is one message of the content stream.
847+type DownloadJobArtifactResponse struct {
848+ state protoimpl.MessageState `protogen:"open.v1"`
849+ // Artifact describes the artifact. Set in the first message of the stream
850+ // only.
851+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
852+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
853+ // message may have an empty chunk. The chunks of a stream add up to the size
854+ // of the artifact minus the offset.
855+ Chunk []byte `protobuf:"bytes,2,opt,name=chunk,proto3" json:"chunk,omitempty"`
856+ unknownFields protoimpl.UnknownFields
857+ sizeCache protoimpl.SizeCache
858+}
859+
860+func (x *DownloadJobArtifactResponse) Reset() {
861+ *x = DownloadJobArtifactResponse{}
862+ mi := &file_ermite_artifact_proto_msgTypes[12]
863+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
864+ ms.StoreMessageInfo(mi)
865+}
866+
867+func (x *DownloadJobArtifactResponse) String() string {
868+ return protoimpl.X.MessageStringOf(x)
869+}
870+
871+func (*DownloadJobArtifactResponse) ProtoMessage() {}
872+
873+func (x *DownloadJobArtifactResponse) ProtoReflect() protoreflect.Message {
874+ mi := &file_ermite_artifact_proto_msgTypes[12]
875+ if x != nil {
876+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
877+ if ms.LoadMessageInfo() == nil {
878+ ms.StoreMessageInfo(mi)
879+ }
880+ return ms
881+ }
882+ return mi.MessageOf(x)
883+}
884+
885+// Deprecated: Use DownloadJobArtifactResponse.ProtoReflect.Descriptor instead.
886+func (*DownloadJobArtifactResponse) Descriptor() ([]byte, []int) {
887+ return file_ermite_artifact_proto_rawDescGZIP(), []int{12}
888+}
889+
890+func (x *DownloadJobArtifactResponse) GetArtifact() *Artifact {
891+ if x != nil {
892+ return x.Artifact
893+ }
894+ return nil
895+}
896+
897+func (x *DownloadJobArtifactResponse) GetChunk() []byte {
898+ if x != nil {
899+ return x.Chunk
900+ }
901+ return nil
902+}
903+
904+// DeleteJobArtifactRequest names the artifact to delete.
905+type DeleteJobArtifactRequest struct {
906+ state protoimpl.MessageState `protogen:"open.v1"`
907+ // JobId is the Job.job_id. It must be the job of the token.
908+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
909+ // Name is the name of a finalized artifact of the job's run.
910+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
911+ unknownFields protoimpl.UnknownFields
912+ sizeCache protoimpl.SizeCache
913+}
914+
915+func (x *DeleteJobArtifactRequest) Reset() {
916+ *x = DeleteJobArtifactRequest{}
917+ mi := &file_ermite_artifact_proto_msgTypes[13]
918+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
919+ ms.StoreMessageInfo(mi)
920+}
921+
922+func (x *DeleteJobArtifactRequest) String() string {
923+ return protoimpl.X.MessageStringOf(x)
924+}
925+
926+func (*DeleteJobArtifactRequest) ProtoMessage() {}
927+
928+func (x *DeleteJobArtifactRequest) ProtoReflect() protoreflect.Message {
929+ mi := &file_ermite_artifact_proto_msgTypes[13]
930+ if x != nil {
931+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
932+ if ms.LoadMessageInfo() == nil {
933+ ms.StoreMessageInfo(mi)
934+ }
935+ return ms
936+ }
937+ return mi.MessageOf(x)
938+}
939+
940+// Deprecated: Use DeleteJobArtifactRequest.ProtoReflect.Descriptor instead.
941+func (*DeleteJobArtifactRequest) Descriptor() ([]byte, []int) {
942+ return file_ermite_artifact_proto_rawDescGZIP(), []int{13}
943+}
944+
945+func (x *DeleteJobArtifactRequest) GetJobId() string {
946+ if x != nil {
947+ return x.JobId
948+ }
949+ return ""
950+}
951+
952+func (x *DeleteJobArtifactRequest) GetName() string {
953+ if x != nil {
954+ return x.Name
955+ }
956+ return ""
957+}
958+
959+// DeleteJobArtifactResponse identifies the deleted artifact.
960+type DeleteJobArtifactResponse struct {
961+ state protoimpl.MessageState `protogen:"open.v1"`
962+ // ArtifactId is the Artifact.id of the artifact that was deleted.
963+ ArtifactId int64 `protobuf:"varint,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
964+ unknownFields protoimpl.UnknownFields
965+ sizeCache protoimpl.SizeCache
966+}
967+
968+func (x *DeleteJobArtifactResponse) Reset() {
969+ *x = DeleteJobArtifactResponse{}
970+ mi := &file_ermite_artifact_proto_msgTypes[14]
971+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
972+ ms.StoreMessageInfo(mi)
973+}
974+
975+func (x *DeleteJobArtifactResponse) String() string {
976+ return protoimpl.X.MessageStringOf(x)
977+}
978+
979+func (*DeleteJobArtifactResponse) ProtoMessage() {}
980+
981+func (x *DeleteJobArtifactResponse) ProtoReflect() protoreflect.Message {
982+ mi := &file_ermite_artifact_proto_msgTypes[14]
983+ if x != nil {
984+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
985+ if ms.LoadMessageInfo() == nil {
986+ ms.StoreMessageInfo(mi)
987+ }
988+ return ms
989+ }
990+ return mi.MessageOf(x)
991+}
992+
993+// Deprecated: Use DeleteJobArtifactResponse.ProtoReflect.Descriptor instead.
994+func (*DeleteJobArtifactResponse) Descriptor() ([]byte, []int) {
995+ return file_ermite_artifact_proto_rawDescGZIP(), []int{14}
996+}
997+
998+func (x *DeleteJobArtifactResponse) GetArtifactId() int64 {
999+ if x != nil {
1000+ return x.ArtifactId
1001+ }
1002+ return 0
1003+}
1004+
1005+// ListArtifactsRequest selects the artifacts of a run.
1006+type ListArtifactsRequest struct {
1007+ state protoimpl.MessageState `protogen:"open.v1"`
1008+ // Repo is the repository name.
1009+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1010+ // RunId is the run.
1011+ RunId int64 `protobuf:"varint,2,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
1012+ unknownFields protoimpl.UnknownFields
1013+ sizeCache protoimpl.SizeCache
1014+}
1015+
1016+func (x *ListArtifactsRequest) Reset() {
1017+ *x = ListArtifactsRequest{}
1018+ mi := &file_ermite_artifact_proto_msgTypes[15]
1019+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1020+ ms.StoreMessageInfo(mi)
1021+}
1022+
1023+func (x *ListArtifactsRequest) String() string {
1024+ return protoimpl.X.MessageStringOf(x)
1025+}
1026+
1027+func (*ListArtifactsRequest) ProtoMessage() {}
1028+
1029+func (x *ListArtifactsRequest) ProtoReflect() protoreflect.Message {
1030+ mi := &file_ermite_artifact_proto_msgTypes[15]
1031+ if x != nil {
1032+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1033+ if ms.LoadMessageInfo() == nil {
1034+ ms.StoreMessageInfo(mi)
1035+ }
1036+ return ms
1037+ }
1038+ return mi.MessageOf(x)
1039+}
1040+
1041+// Deprecated: Use ListArtifactsRequest.ProtoReflect.Descriptor instead.
1042+func (*ListArtifactsRequest) Descriptor() ([]byte, []int) {
1043+ return file_ermite_artifact_proto_rawDescGZIP(), []int{15}
1044+}
1045+
1046+func (x *ListArtifactsRequest) GetRepo() string {
1047+ if x != nil {
1048+ return x.Repo
1049+ }
1050+ return ""
1051+}
1052+
1053+func (x *ListArtifactsRequest) GetRunId() int64 {
1054+ if x != nil {
1055+ return x.RunId
1056+ }
1057+ return 0
1058+}
1059+
1060+// ListArtifactsResponse lists the artifacts of a run.
1061+type ListArtifactsResponse struct {
1062+ state protoimpl.MessageState `protogen:"open.v1"`
1063+ // Artifacts are the artifacts of the run, all attempts, by id.
1064+ Artifacts []*Artifact `protobuf:"bytes,1,rep,name=artifacts,proto3" json:"artifacts,omitempty"`
1065+ // UsedBytes is the space that all the artifacts of the repository use,
1066+ // uploads in progress included.
1067+ UsedBytes int64 `protobuf:"varint,2,opt,name=used_bytes,json=usedBytes,proto3" json:"used_bytes,omitempty"`
1068+ // QuotaBytes is the space the artifacts of the repository may use.
1069+ QuotaBytes int64 `protobuf:"varint,3,opt,name=quota_bytes,json=quotaBytes,proto3" json:"quota_bytes,omitempty"`
1070+ unknownFields protoimpl.UnknownFields
1071+ sizeCache protoimpl.SizeCache
1072+}
1073+
1074+func (x *ListArtifactsResponse) Reset() {
1075+ *x = ListArtifactsResponse{}
1076+ mi := &file_ermite_artifact_proto_msgTypes[16]
1077+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1078+ ms.StoreMessageInfo(mi)
1079+}
1080+
1081+func (x *ListArtifactsResponse) String() string {
1082+ return protoimpl.X.MessageStringOf(x)
1083+}
1084+
1085+func (*ListArtifactsResponse) ProtoMessage() {}
1086+
1087+func (x *ListArtifactsResponse) ProtoReflect() protoreflect.Message {
1088+ mi := &file_ermite_artifact_proto_msgTypes[16]
1089+ if x != nil {
1090+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1091+ if ms.LoadMessageInfo() == nil {
1092+ ms.StoreMessageInfo(mi)
1093+ }
1094+ return ms
1095+ }
1096+ return mi.MessageOf(x)
1097+}
1098+
1099+// Deprecated: Use ListArtifactsResponse.ProtoReflect.Descriptor instead.
1100+func (*ListArtifactsResponse) Descriptor() ([]byte, []int) {
1101+ return file_ermite_artifact_proto_rawDescGZIP(), []int{16}
1102+}
1103+
1104+func (x *ListArtifactsResponse) GetArtifacts() []*Artifact {
1105+ if x != nil {
1106+ return x.Artifacts
1107+ }
1108+ return nil
1109+}
1110+
1111+func (x *ListArtifactsResponse) GetUsedBytes() int64 {
1112+ if x != nil {
1113+ return x.UsedBytes
1114+ }
1115+ return 0
1116+}
1117+
1118+func (x *ListArtifactsResponse) GetQuotaBytes() int64 {
1119+ if x != nil {
1120+ return x.QuotaBytes
1121+ }
1122+ return 0
1123+}
1124+
1125+// DownloadArtifactRequest selects the content of an artifact.
1126+type DownloadArtifactRequest struct {
1127+ state protoimpl.MessageState `protogen:"open.v1"`
1128+ // Repo is the repository name.
1129+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1130+ // ArtifactId is the Artifact.id.
1131+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
1132+ // Offset is the first byte to send, from 0 to the size of the artifact.
1133+ Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
1134+ unknownFields protoimpl.UnknownFields
1135+ sizeCache protoimpl.SizeCache
1136+}
1137+
1138+func (x *DownloadArtifactRequest) Reset() {
1139+ *x = DownloadArtifactRequest{}
1140+ mi := &file_ermite_artifact_proto_msgTypes[17]
1141+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1142+ ms.StoreMessageInfo(mi)
1143+}
1144+
1145+func (x *DownloadArtifactRequest) String() string {
1146+ return protoimpl.X.MessageStringOf(x)
1147+}
1148+
1149+func (*DownloadArtifactRequest) ProtoMessage() {}
1150+
1151+func (x *DownloadArtifactRequest) ProtoReflect() protoreflect.Message {
1152+ mi := &file_ermite_artifact_proto_msgTypes[17]
1153+ if x != nil {
1154+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1155+ if ms.LoadMessageInfo() == nil {
1156+ ms.StoreMessageInfo(mi)
1157+ }
1158+ return ms
1159+ }
1160+ return mi.MessageOf(x)
1161+}
1162+
1163+// Deprecated: Use DownloadArtifactRequest.ProtoReflect.Descriptor instead.
1164+func (*DownloadArtifactRequest) Descriptor() ([]byte, []int) {
1165+ return file_ermite_artifact_proto_rawDescGZIP(), []int{17}
1166+}
1167+
1168+func (x *DownloadArtifactRequest) GetRepo() string {
1169+ if x != nil {
1170+ return x.Repo
1171+ }
1172+ return ""
1173+}
1174+
1175+func (x *DownloadArtifactRequest) GetArtifactId() int64 {
1176+ if x != nil {
1177+ return x.ArtifactId
1178+ }
1179+ return 0
1180+}
1181+
1182+func (x *DownloadArtifactRequest) GetOffset() int64 {
1183+ if x != nil {
1184+ return x.Offset
1185+ }
1186+ return 0
1187+}
1188+
1189+// DownloadArtifactResponse is one message of the content stream.
1190+type DownloadArtifactResponse struct {
1191+ state protoimpl.MessageState `protogen:"open.v1"`
1192+ // Artifact describes the artifact. Set in the first message of the stream
1193+ // only.
1194+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
1195+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
1196+ // message may have an empty chunk.
1197+ Chunk []byte `protobuf:"bytes,2,opt,name=chunk,proto3" json:"chunk,omitempty"`
1198+ unknownFields protoimpl.UnknownFields
1199+ sizeCache protoimpl.SizeCache
1200+}
1201+
1202+func (x *DownloadArtifactResponse) Reset() {
1203+ *x = DownloadArtifactResponse{}
1204+ mi := &file_ermite_artifact_proto_msgTypes[18]
1205+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1206+ ms.StoreMessageInfo(mi)
1207+}
1208+
1209+func (x *DownloadArtifactResponse) String() string {
1210+ return protoimpl.X.MessageStringOf(x)
1211+}
1212+
1213+func (*DownloadArtifactResponse) ProtoMessage() {}
1214+
1215+func (x *DownloadArtifactResponse) ProtoReflect() protoreflect.Message {
1216+ mi := &file_ermite_artifact_proto_msgTypes[18]
1217+ if x != nil {
1218+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1219+ if ms.LoadMessageInfo() == nil {
1220+ ms.StoreMessageInfo(mi)
1221+ }
1222+ return ms
1223+ }
1224+ return mi.MessageOf(x)
1225+}
1226+
1227+// Deprecated: Use DownloadArtifactResponse.ProtoReflect.Descriptor instead.
1228+func (*DownloadArtifactResponse) Descriptor() ([]byte, []int) {
1229+ return file_ermite_artifact_proto_rawDescGZIP(), []int{18}
1230+}
1231+
1232+func (x *DownloadArtifactResponse) GetArtifact() *Artifact {
1233+ if x != nil {
1234+ return x.Artifact
1235+ }
1236+ return nil
1237+}
1238+
1239+func (x *DownloadArtifactResponse) GetChunk() []byte {
1240+ if x != nil {
1241+ return x.Chunk
1242+ }
1243+ return nil
1244+}
1245+
1246+// DeleteArtifactRequest names the artifact to delete.
1247+type DeleteArtifactRequest struct {
1248+ state protoimpl.MessageState `protogen:"open.v1"`
1249+ // Repo is the repository name.
1250+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1251+ // ArtifactId is the Artifact.id.
1252+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
1253+ unknownFields protoimpl.UnknownFields
1254+ sizeCache protoimpl.SizeCache
1255+}
1256+
1257+func (x *DeleteArtifactRequest) Reset() {
1258+ *x = DeleteArtifactRequest{}
1259+ mi := &file_ermite_artifact_proto_msgTypes[19]
1260+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1261+ ms.StoreMessageInfo(mi)
1262+}
1263+
1264+func (x *DeleteArtifactRequest) String() string {
1265+ return protoimpl.X.MessageStringOf(x)
1266+}
1267+
1268+func (*DeleteArtifactRequest) ProtoMessage() {}
1269+
1270+func (x *DeleteArtifactRequest) ProtoReflect() protoreflect.Message {
1271+ mi := &file_ermite_artifact_proto_msgTypes[19]
1272+ if x != nil {
1273+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1274+ if ms.LoadMessageInfo() == nil {
1275+ ms.StoreMessageInfo(mi)
1276+ }
1277+ return ms
1278+ }
1279+ return mi.MessageOf(x)
1280+}
1281+
1282+// Deprecated: Use DeleteArtifactRequest.ProtoReflect.Descriptor instead.
1283+func (*DeleteArtifactRequest) Descriptor() ([]byte, []int) {
1284+ return file_ermite_artifact_proto_rawDescGZIP(), []int{19}
1285+}
1286+
1287+func (x *DeleteArtifactRequest) GetRepo() string {
1288+ if x != nil {
1289+ return x.Repo
1290+ }
1291+ return ""
1292+}
1293+
1294+func (x *DeleteArtifactRequest) GetArtifactId() int64 {
1295+ if x != nil {
1296+ return x.ArtifactId
1297+ }
1298+ return 0
1299+}
1300+
1301+// DeleteArtifactResponse is empty.
1302+type DeleteArtifactResponse struct {
1303+ state protoimpl.MessageState `protogen:"open.v1"`
1304+ unknownFields protoimpl.UnknownFields
1305+ sizeCache protoimpl.SizeCache
1306+}
1307+
1308+func (x *DeleteArtifactResponse) Reset() {
1309+ *x = DeleteArtifactResponse{}
1310+ mi := &file_ermite_artifact_proto_msgTypes[20]
1311+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1312+ ms.StoreMessageInfo(mi)
1313+}
1314+
1315+func (x *DeleteArtifactResponse) String() string {
1316+ return protoimpl.X.MessageStringOf(x)
1317+}
1318+
1319+func (*DeleteArtifactResponse) ProtoMessage() {}
1320+
1321+func (x *DeleteArtifactResponse) ProtoReflect() protoreflect.Message {
1322+ mi := &file_ermite_artifact_proto_msgTypes[20]
1323+ if x != nil {
1324+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1325+ if ms.LoadMessageInfo() == nil {
1326+ ms.StoreMessageInfo(mi)
1327+ }
1328+ return ms
1329+ }
1330+ return mi.MessageOf(x)
1331+}
1332+
1333+// Deprecated: Use DeleteArtifactResponse.ProtoReflect.Descriptor instead.
1334+func (*DeleteArtifactResponse) Descriptor() ([]byte, []int) {
1335+ return file_ermite_artifact_proto_rawDescGZIP(), []int{20}
1336+}
1337+
1338+var File_ermite_artifact_proto protoreflect.FileDescriptor
1339+
1340+const file_ermite_artifact_proto_rawDesc = "" +
1341+ "\n" +
1342+ "\x15ermite/artifact.proto\x12\x06ermite\x1a\x1fgoogle/protobuf/timestamp.proto\"\xcb\x02\n" +
1343+ "\bArtifact\x12\x0e\n" +
1344+ "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" +
1345+ "\x04repo\x18\x02 \x01(\tR\x04repo\x12\x15\n" +
1346+ "\x06run_id\x18\x03 \x01(\x03R\x05runId\x12\x18\n" +
1347+ "\aattempt\x18\x04 \x01(\x05R\aattempt\x12\x15\n" +
1348+ "\x06job_id\x18\x05 \x01(\tR\x05jobId\x12\x12\n" +
1349+ "\x04name\x18\x06 \x01(\tR\x04name\x12\x12\n" +
1350+ "\x04size\x18\a \x01(\x03R\x04size\x12\x16\n" +
1351+ "\x06digest\x18\b \x01(\tR\x06digest\x12\x1d\n" +
1352+ "\n" +
1353+ "media_type\x18\t \x01(\tR\tmediaType\x129\n" +
1354+ "\n" +
1355+ "created_at\x18\n" +
1356+ " \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
1357+ "\n" +
1358+ "expires_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"\x9f\x01\n" +
1359+ "\x18CreateJobArtifactRequest\x12\x15\n" +
1360+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1361+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x1d\n" +
1362+ "\n" +
1363+ "media_type\x18\x03 \x01(\tR\tmediaType\x129\n" +
1364+ "\n" +
1365+ "expires_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"w\n" +
1366+ "\x19CreateJobArtifactResponse\x12\x1f\n" +
1367+ "\vartifact_id\x18\x01 \x01(\x03R\n" +
1368+ "artifactId\x129\n" +
1369+ "\n" +
1370+ "expires_at\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"\x86\x01\n" +
1371+ "\x1dUploadJobArtifactBlockRequest\x12\x15\n" +
1372+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1373+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1374+ "artifactId\x12\x19\n" +
1375+ "\bblock_id\x18\x03 \x01(\fR\ablockId\x12\x12\n" +
1376+ "\x04data\x18\x04 \x01(\fR\x04data\"4\n" +
1377+ "\x1eUploadJobArtifactBlockResponse\x12\x12\n" +
1378+ "\x04size\x18\x01 \x01(\x03R\x04size\"o\n" +
1379+ "\x18CommitJobArtifactRequest\x12\x15\n" +
1380+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1381+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1382+ "artifactId\x12\x1b\n" +
1383+ "\tblock_ids\x18\x03 \x03(\fR\bblockIds\"G\n" +
1384+ "\x19CommitJobArtifactResponse\x12\x12\n" +
1385+ "\x04size\x18\x01 \x01(\x03R\x04size\x12\x16\n" +
1386+ "\x06digest\x18\x02 \x01(\tR\x06digest\"s\n" +
1387+ "\x1aFinalizeJobArtifactRequest\x12\x15\n" +
1388+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1389+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
1390+ "\x04size\x18\x03 \x01(\x03R\x04size\x12\x16\n" +
1391+ "\x06digest\x18\x04 \x01(\tR\x06digest\"K\n" +
1392+ "\x1bFinalizeJobArtifactResponse\x12,\n" +
1393+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\"e\n" +
1394+ "\x17ListJobArtifactsRequest\x12\x15\n" +
1395+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1396+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" +
1397+ "\vartifact_id\x18\x03 \x01(\x03R\n" +
1398+ "artifactId\"J\n" +
1399+ "\x18ListJobArtifactsResponse\x12.\n" +
1400+ "\tartifacts\x18\x01 \x03(\v2\x10.ermite.ArtifactR\tartifacts\"l\n" +
1401+ "\x1aDownloadJobArtifactRequest\x12\x15\n" +
1402+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1403+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1404+ "artifactId\x12\x16\n" +
1405+ "\x06offset\x18\x03 \x01(\x03R\x06offset\"a\n" +
1406+ "\x1bDownloadJobArtifactResponse\x12,\n" +
1407+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\x12\x14\n" +
1408+ "\x05chunk\x18\x02 \x01(\fR\x05chunk\"E\n" +
1409+ "\x18DeleteJobArtifactRequest\x12\x15\n" +
1410+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1411+ "\x04name\x18\x02 \x01(\tR\x04name\"<\n" +
1412+ "\x19DeleteJobArtifactResponse\x12\x1f\n" +
1413+ "\vartifact_id\x18\x01 \x01(\x03R\n" +
1414+ "artifactId\"A\n" +
1415+ "\x14ListArtifactsRequest\x12\x12\n" +
1416+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x15\n" +
1417+ "\x06run_id\x18\x02 \x01(\x03R\x05runId\"\x87\x01\n" +
1418+ "\x15ListArtifactsResponse\x12.\n" +
1419+ "\tartifacts\x18\x01 \x03(\v2\x10.ermite.ArtifactR\tartifacts\x12\x1d\n" +
1420+ "\n" +
1421+ "used_bytes\x18\x02 \x01(\x03R\tusedBytes\x12\x1f\n" +
1422+ "\vquota_bytes\x18\x03 \x01(\x03R\n" +
1423+ "quotaBytes\"f\n" +
1424+ "\x17DownloadArtifactRequest\x12\x12\n" +
1425+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x1f\n" +
1426+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1427+ "artifactId\x12\x16\n" +
1428+ "\x06offset\x18\x03 \x01(\x03R\x06offset\"^\n" +
1429+ "\x18DownloadArtifactResponse\x12,\n" +
1430+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\x12\x14\n" +
1431+ "\x05chunk\x18\x02 \x01(\fR\x05chunk\"L\n" +
1432+ "\x15DeleteArtifactRequest\x12\x12\n" +
1433+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x1f\n" +
1434+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1435+ "artifactId\"\x18\n" +
1436+ "\x16DeleteArtifactResponse2\xa6\x05\n" +
1437+ "\x12JobArtifactService\x12X\n" +
1438+ "\x11CreateJobArtifact\x12 .ermite.CreateJobArtifactRequest\x1a!.ermite.CreateJobArtifactResponse\x12i\n" +
1439+ "\x16UploadJobArtifactBlock\x12%.ermite.UploadJobArtifactBlockRequest\x1a&.ermite.UploadJobArtifactBlockResponse(\x01\x12X\n" +
1440+ "\x11CommitJobArtifact\x12 .ermite.CommitJobArtifactRequest\x1a!.ermite.CommitJobArtifactResponse\x12^\n" +
1441+ "\x13FinalizeJobArtifact\x12\".ermite.FinalizeJobArtifactRequest\x1a#.ermite.FinalizeJobArtifactResponse\x12U\n" +
1442+ "\x10ListJobArtifacts\x12\x1f.ermite.ListJobArtifactsRequest\x1a .ermite.ListJobArtifactsResponse\x12`\n" +
1443+ "\x13DownloadJobArtifact\x12\".ermite.DownloadJobArtifactRequest\x1a#.ermite.DownloadJobArtifactResponse0\x01\x12X\n" +
1444+ "\x11DeleteJobArtifact\x12 .ermite.DeleteJobArtifactRequest\x1a!.ermite.DeleteJobArtifactResponse2\x89\x02\n" +
1445+ "\x0fArtifactService\x12L\n" +
1446+ "\rListArtifacts\x12\x1c.ermite.ListArtifactsRequest\x1a\x1d.ermite.ListArtifactsResponse\x12W\n" +
1447+ "\x10DownloadArtifact\x12\x1f.ermite.DownloadArtifactRequest\x1a .ermite.DownloadArtifactResponse0\x01\x12O\n" +
1448+ "\x0eDeleteArtifact\x12\x1d.ermite.DeleteArtifactRequest\x1a\x1e.ermite.DeleteArtifactResponseBt\n" +
1449+ "\n" +
1450+ "com.ermiteB\rArtifactProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
1451+
1452+var (
1453+ file_ermite_artifact_proto_rawDescOnce sync.Once
1454+ file_ermite_artifact_proto_rawDescData []byte
1455+)
1456+
1457+func file_ermite_artifact_proto_rawDescGZIP() []byte {
1458+ file_ermite_artifact_proto_rawDescOnce.Do(func() {
1459+ file_ermite_artifact_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ermite_artifact_proto_rawDesc), len(file_ermite_artifact_proto_rawDesc)))
1460+ })
1461+ return file_ermite_artifact_proto_rawDescData
1462+}
1463+
1464+var file_ermite_artifact_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
1465+var file_ermite_artifact_proto_goTypes = []any{
1466+ (*Artifact)(nil), // 0: ermite.Artifact
1467+ (*CreateJobArtifactRequest)(nil), // 1: ermite.CreateJobArtifactRequest
1468+ (*CreateJobArtifactResponse)(nil), // 2: ermite.CreateJobArtifactResponse
1469+ (*UploadJobArtifactBlockRequest)(nil), // 3: ermite.UploadJobArtifactBlockRequest
1470+ (*UploadJobArtifactBlockResponse)(nil), // 4: ermite.UploadJobArtifactBlockResponse
1471+ (*CommitJobArtifactRequest)(nil), // 5: ermite.CommitJobArtifactRequest
1472+ (*CommitJobArtifactResponse)(nil), // 6: ermite.CommitJobArtifactResponse
1473+ (*FinalizeJobArtifactRequest)(nil), // 7: ermite.FinalizeJobArtifactRequest
1474+ (*FinalizeJobArtifactResponse)(nil), // 8: ermite.FinalizeJobArtifactResponse
1475+ (*ListJobArtifactsRequest)(nil), // 9: ermite.ListJobArtifactsRequest
1476+ (*ListJobArtifactsResponse)(nil), // 10: ermite.ListJobArtifactsResponse
1477+ (*DownloadJobArtifactRequest)(nil), // 11: ermite.DownloadJobArtifactRequest
1478+ (*DownloadJobArtifactResponse)(nil), // 12: ermite.DownloadJobArtifactResponse
1479+ (*DeleteJobArtifactRequest)(nil), // 13: ermite.DeleteJobArtifactRequest
1480+ (*DeleteJobArtifactResponse)(nil), // 14: ermite.DeleteJobArtifactResponse
1481+ (*ListArtifactsRequest)(nil), // 15: ermite.ListArtifactsRequest
1482+ (*ListArtifactsResponse)(nil), // 16: ermite.ListArtifactsResponse
1483+ (*DownloadArtifactRequest)(nil), // 17: ermite.DownloadArtifactRequest
1484+ (*DownloadArtifactResponse)(nil), // 18: ermite.DownloadArtifactResponse
1485+ (*DeleteArtifactRequest)(nil), // 19: ermite.DeleteArtifactRequest
1486+ (*DeleteArtifactResponse)(nil), // 20: ermite.DeleteArtifactResponse
1487+ (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
1488+}
1489+var file_ermite_artifact_proto_depIdxs = []int32{
1490+ 21, // 0: ermite.Artifact.created_at:type_name -> google.protobuf.Timestamp
1491+ 21, // 1: ermite.Artifact.expires_at:type_name -> google.protobuf.Timestamp
1492+ 21, // 2: ermite.CreateJobArtifactRequest.expires_at:type_name -> google.protobuf.Timestamp
1493+ 21, // 3: ermite.CreateJobArtifactResponse.expires_at:type_name -> google.protobuf.Timestamp
1494+ 0, // 4: ermite.FinalizeJobArtifactResponse.artifact:type_name -> ermite.Artifact
1495+ 0, // 5: ermite.ListJobArtifactsResponse.artifacts:type_name -> ermite.Artifact
1496+ 0, // 6: ermite.DownloadJobArtifactResponse.artifact:type_name -> ermite.Artifact
1497+ 0, // 7: ermite.ListArtifactsResponse.artifacts:type_name -> ermite.Artifact
1498+ 0, // 8: ermite.DownloadArtifactResponse.artifact:type_name -> ermite.Artifact
1499+ 1, // 9: ermite.JobArtifactService.CreateJobArtifact:input_type -> ermite.CreateJobArtifactRequest
1500+ 3, // 10: ermite.JobArtifactService.UploadJobArtifactBlock:input_type -> ermite.UploadJobArtifactBlockRequest
1501+ 5, // 11: ermite.JobArtifactService.CommitJobArtifact:input_type -> ermite.CommitJobArtifactRequest
1502+ 7, // 12: ermite.JobArtifactService.FinalizeJobArtifact:input_type -> ermite.FinalizeJobArtifactRequest
1503+ 9, // 13: ermite.JobArtifactService.ListJobArtifacts:input_type -> ermite.ListJobArtifactsRequest
1504+ 11, // 14: ermite.JobArtifactService.DownloadJobArtifact:input_type -> ermite.DownloadJobArtifactRequest
1505+ 13, // 15: ermite.JobArtifactService.DeleteJobArtifact:input_type -> ermite.DeleteJobArtifactRequest
1506+ 15, // 16: ermite.ArtifactService.ListArtifacts:input_type -> ermite.ListArtifactsRequest
1507+ 17, // 17: ermite.ArtifactService.DownloadArtifact:input_type -> ermite.DownloadArtifactRequest
1508+ 19, // 18: ermite.ArtifactService.DeleteArtifact:input_type -> ermite.DeleteArtifactRequest
1509+ 2, // 19: ermite.JobArtifactService.CreateJobArtifact:output_type -> ermite.CreateJobArtifactResponse
1510+ 4, // 20: ermite.JobArtifactService.UploadJobArtifactBlock:output_type -> ermite.UploadJobArtifactBlockResponse
1511+ 6, // 21: ermite.JobArtifactService.CommitJobArtifact:output_type -> ermite.CommitJobArtifactResponse
1512+ 8, // 22: ermite.JobArtifactService.FinalizeJobArtifact:output_type -> ermite.FinalizeJobArtifactResponse
1513+ 10, // 23: ermite.JobArtifactService.ListJobArtifacts:output_type -> ermite.ListJobArtifactsResponse
1514+ 12, // 24: ermite.JobArtifactService.DownloadJobArtifact:output_type -> ermite.DownloadJobArtifactResponse
1515+ 14, // 25: ermite.JobArtifactService.DeleteJobArtifact:output_type -> ermite.DeleteJobArtifactResponse
1516+ 16, // 26: ermite.ArtifactService.ListArtifacts:output_type -> ermite.ListArtifactsResponse
1517+ 18, // 27: ermite.ArtifactService.DownloadArtifact:output_type -> ermite.DownloadArtifactResponse
1518+ 20, // 28: ermite.ArtifactService.DeleteArtifact:output_type -> ermite.DeleteArtifactResponse
1519+ 19, // [19:29] is the sub-list for method output_type
1520+ 9, // [9:19] is the sub-list for method input_type
1521+ 9, // [9:9] is the sub-list for extension type_name
1522+ 9, // [9:9] is the sub-list for extension extendee
1523+ 0, // [0:9] is the sub-list for field type_name
1524+}
1525+
1526+func init() { file_ermite_artifact_proto_init() }
1527+func file_ermite_artifact_proto_init() {
1528+ if File_ermite_artifact_proto != nil {
1529+ return
1530+ }
1531+ type x struct{}
1532+ out := protoimpl.TypeBuilder{
1533+ File: protoimpl.DescBuilder{
1534+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
1535+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_artifact_proto_rawDesc), len(file_ermite_artifact_proto_rawDesc)),
1536+ NumEnums: 0,
1537+ NumMessages: 21,
1538+ NumExtensions: 0,
1539+ NumServices: 2,
1540+ },
1541+ GoTypes: file_ermite_artifact_proto_goTypes,
1542+ DependencyIndexes: file_ermite_artifact_proto_depIdxs,
1543+ MessageInfos: file_ermite_artifact_proto_msgTypes,
1544+ }.Build()
1545+ File_ermite_artifact_proto = out.File
1546+ file_ermite_artifact_proto_goTypes = nil
1547+ file_ermite_artifact_proto_depIdxs = nil
1548+}
@@ -0,0 +1,1548 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-go. DO NOT EDIT.
4+// versions:
5+// protoc-gen-go v1.36.12
6+// protoc (unknown)
7+// source: ermite/artifact.proto
8+
9+package ermite
10+
11+import (
12+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
13+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
14+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
15+ reflect "reflect"
16+ sync "sync"
17+ unsafe "unsafe"
18+)
19+
20+const (
21+ // Verify that this generated code is sufficiently up-to-date.
22+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
23+ // Verify that runtime/protoimpl is sufficiently up-to-date.
24+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
25+)
26+
27+// Artifact is a file that a job of a run uploaded with actions/upload-artifact
28+// (artifacts v4): in most cases a zip archive, or a single file uploaded as is
29+// ("archive: false"). It belongs to a run, not to one attempt: every job of the
30+// run, in any attempt, sees the artifacts of the run. Only finalized artifacts
31+// are described; an upload in progress is invisible.
32+type Artifact struct {
33+ state protoimpl.MessageState `protogen:"open.v1"`
34+ // Id identifies the artifact on the server: unique across repositories and
35+ // runs, never reused, and higher for a later artifact. It is GitHub's
36+ // "artifact id" (databaseId), the id of the REST API.
37+ Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
38+ // Repo is the name of the repository of the run.
39+ Repo string `protobuf:"bytes,2,opt,name=repo,proto3" json:"repo,omitempty"`
40+ // RunId is the run the artifact belongs to.
41+ RunId int64 `protobuf:"varint,3,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
42+ // Attempt is the attempt of the run whose job uploaded it.
43+ Attempt int32 `protobuf:"varint,4,opt,name=attempt,proto3" json:"attempt,omitempty"`
44+ // JobId is the Job.job_id of the job that uploaded it.
45+ JobId string `protobuf:"bytes,5,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
46+ // Name is the name of the artifact, unique among the artifacts of the run:
47+ // 1 to 256 characters of valid UTF-8, without control characters, '"', ':',
48+ // '<', '>', '|', '*', '?', '\' or '/' (the characters @actions/artifact
49+ // refuses).
50+ Name string `protobuf:"bytes,6,opt,name=name,proto3" json:"name,omitempty"`
51+ // Size is the number of bytes of the content.
52+ Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"`
53+ // Digest is the SHA-256 of the content, "sha256:" and 64 lowercase
54+ // hexadecimal characters, as GitHub gives it.
55+ Digest string `protobuf:"bytes,8,opt,name=digest,proto3" json:"digest,omitempty"`
56+ // MediaType is the media type of the content: "application/zip" for an
57+ // archive, the type the uploader gave for a file uploaded as is.
58+ MediaType string `protobuf:"bytes,9,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"`
59+ // CreatedAt is when the upload began.
60+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
61+ // ExpiresAt is when the server deletes the artifact (see
62+ // CreateJobArtifactRequest.expires_at).
63+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
64+ unknownFields protoimpl.UnknownFields
65+ sizeCache protoimpl.SizeCache
66+}
67+
68+func (x *Artifact) Reset() {
69+ *x = Artifact{}
70+ mi := &file_ermite_artifact_proto_msgTypes[0]
71+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
72+ ms.StoreMessageInfo(mi)
73+}
74+
75+func (x *Artifact) String() string {
76+ return protoimpl.X.MessageStringOf(x)
77+}
78+
79+func (*Artifact) ProtoMessage() {}
80+
81+func (x *Artifact) ProtoReflect() protoreflect.Message {
82+ mi := &file_ermite_artifact_proto_msgTypes[0]
83+ if x != nil {
84+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
85+ if ms.LoadMessageInfo() == nil {
86+ ms.StoreMessageInfo(mi)
87+ }
88+ return ms
89+ }
90+ return mi.MessageOf(x)
91+}
92+
93+// Deprecated: Use Artifact.ProtoReflect.Descriptor instead.
94+func (*Artifact) Descriptor() ([]byte, []int) {
95+ return file_ermite_artifact_proto_rawDescGZIP(), []int{0}
96+}
97+
98+func (x *Artifact) GetId() int64 {
99+ if x != nil {
100+ return x.Id
101+ }
102+ return 0
103+}
104+
105+func (x *Artifact) GetRepo() string {
106+ if x != nil {
107+ return x.Repo
108+ }
109+ return ""
110+}
111+
112+func (x *Artifact) GetRunId() int64 {
113+ if x != nil {
114+ return x.RunId
115+ }
116+ return 0
117+}
118+
119+func (x *Artifact) GetAttempt() int32 {
120+ if x != nil {
121+ return x.Attempt
122+ }
123+ return 0
124+}
125+
126+func (x *Artifact) GetJobId() string {
127+ if x != nil {
128+ return x.JobId
129+ }
130+ return ""
131+}
132+
133+func (x *Artifact) GetName() string {
134+ if x != nil {
135+ return x.Name
136+ }
137+ return ""
138+}
139+
140+func (x *Artifact) GetSize() int64 {
141+ if x != nil {
142+ return x.Size
143+ }
144+ return 0
145+}
146+
147+func (x *Artifact) GetDigest() string {
148+ if x != nil {
149+ return x.Digest
150+ }
151+ return ""
152+}
153+
154+func (x *Artifact) GetMediaType() string {
155+ if x != nil {
156+ return x.MediaType
157+ }
158+ return ""
159+}
160+
161+func (x *Artifact) GetCreatedAt() *timestamppb.Timestamp {
162+ if x != nil {
163+ return x.CreatedAt
164+ }
165+ return nil
166+}
167+
168+func (x *Artifact) GetExpiresAt() *timestamppb.Timestamp {
169+ if x != nil {
170+ return x.ExpiresAt
171+ }
172+ return nil
173+}
174+
175+// CreateJobArtifactRequest begins an upload.
176+type CreateJobArtifactRequest struct {
177+ state protoimpl.MessageState `protogen:"open.v1"`
178+ // JobId is the Job.job_id. It must be the job of the token.
179+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
180+ // Name is the name of the artifact, see Artifact.name.
181+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
182+ // MediaType is the media type of a file uploaded as is (the toolkit's
183+ // mime_type), at most 255 characters. Empty means "application/zip".
184+ MediaType string `protobuf:"bytes,3,opt,name=media_type,json=mediaType,proto3" json:"media_type,omitempty"`
185+ // ExpiresAt is when the artifact should be deleted (the toolkit's
186+ // expires_at, from "retention-days"). Unset means the default retention of
187+ // the server. The server keeps it between one day from now and its longest
188+ // retention, and returns the time it kept.
189+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
190+ unknownFields protoimpl.UnknownFields
191+ sizeCache protoimpl.SizeCache
192+}
193+
194+func (x *CreateJobArtifactRequest) Reset() {
195+ *x = CreateJobArtifactRequest{}
196+ mi := &file_ermite_artifact_proto_msgTypes[1]
197+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
198+ ms.StoreMessageInfo(mi)
199+}
200+
201+func (x *CreateJobArtifactRequest) String() string {
202+ return protoimpl.X.MessageStringOf(x)
203+}
204+
205+func (*CreateJobArtifactRequest) ProtoMessage() {}
206+
207+func (x *CreateJobArtifactRequest) ProtoReflect() protoreflect.Message {
208+ mi := &file_ermite_artifact_proto_msgTypes[1]
209+ if x != nil {
210+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
211+ if ms.LoadMessageInfo() == nil {
212+ ms.StoreMessageInfo(mi)
213+ }
214+ return ms
215+ }
216+ return mi.MessageOf(x)
217+}
218+
219+// Deprecated: Use CreateJobArtifactRequest.ProtoReflect.Descriptor instead.
220+func (*CreateJobArtifactRequest) Descriptor() ([]byte, []int) {
221+ return file_ermite_artifact_proto_rawDescGZIP(), []int{1}
222+}
223+
224+func (x *CreateJobArtifactRequest) GetJobId() string {
225+ if x != nil {
226+ return x.JobId
227+ }
228+ return ""
229+}
230+
231+func (x *CreateJobArtifactRequest) GetName() string {
232+ if x != nil {
233+ return x.Name
234+ }
235+ return ""
236+}
237+
238+func (x *CreateJobArtifactRequest) GetMediaType() string {
239+ if x != nil {
240+ return x.MediaType
241+ }
242+ return ""
243+}
244+
245+func (x *CreateJobArtifactRequest) GetExpiresAt() *timestamppb.Timestamp {
246+ if x != nil {
247+ return x.ExpiresAt
248+ }
249+ return nil
250+}
251+
252+// CreateJobArtifactResponse identifies the pending artifact.
253+type CreateJobArtifactResponse struct {
254+ state protoimpl.MessageState `protogen:"open.v1"`
255+ // ArtifactId is the id the artifact will have once finalized (Artifact.id).
256+ ArtifactId int64 `protobuf:"varint,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
257+ // ExpiresAt is the expiry the server kept.
258+ ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expires_at,json=expiresAt,proto3" json:"expires_at,omitempty"`
259+ unknownFields protoimpl.UnknownFields
260+ sizeCache protoimpl.SizeCache
261+}
262+
263+func (x *CreateJobArtifactResponse) Reset() {
264+ *x = CreateJobArtifactResponse{}
265+ mi := &file_ermite_artifact_proto_msgTypes[2]
266+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
267+ ms.StoreMessageInfo(mi)
268+}
269+
270+func (x *CreateJobArtifactResponse) String() string {
271+ return protoimpl.X.MessageStringOf(x)
272+}
273+
274+func (*CreateJobArtifactResponse) ProtoMessage() {}
275+
276+func (x *CreateJobArtifactResponse) ProtoReflect() protoreflect.Message {
277+ mi := &file_ermite_artifact_proto_msgTypes[2]
278+ if x != nil {
279+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
280+ if ms.LoadMessageInfo() == nil {
281+ ms.StoreMessageInfo(mi)
282+ }
283+ return ms
284+ }
285+ return mi.MessageOf(x)
286+}
287+
288+// Deprecated: Use CreateJobArtifactResponse.ProtoReflect.Descriptor instead.
289+func (*CreateJobArtifactResponse) Descriptor() ([]byte, []int) {
290+ return file_ermite_artifact_proto_rawDescGZIP(), []int{2}
291+}
292+
293+func (x *CreateJobArtifactResponse) GetArtifactId() int64 {
294+ if x != nil {
295+ return x.ArtifactId
296+ }
297+ return 0
298+}
299+
300+func (x *CreateJobArtifactResponse) GetExpiresAt() *timestamppb.Timestamp {
301+ if x != nil {
302+ return x.ExpiresAt
303+ }
304+ return nil
305+}
306+
307+// UploadJobArtifactBlockRequest is one message of the stream of a block.
308+type UploadJobArtifactBlockRequest struct {
309+ state protoimpl.MessageState `protogen:"open.v1"`
310+ // JobId is the Job.job_id, in the first message only. It must be the job of
311+ // the token.
312+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
313+ // ArtifactId is the CreateJobArtifactResponse.artifact_id, in the first
314+ // message only.
315+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
316+ // BlockId identifies the block within the artifact: 1 to 64 bytes (Azure's
317+ // block id, decoded from base64), in the first message only.
318+ BlockId []byte `protobuf:"bytes,3,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
319+ // Data is the next part of the block, at most 1 MiB (1,048,576 bytes). Any
320+ // message may have none.
321+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
322+ unknownFields protoimpl.UnknownFields
323+ sizeCache protoimpl.SizeCache
324+}
325+
326+func (x *UploadJobArtifactBlockRequest) Reset() {
327+ *x = UploadJobArtifactBlockRequest{}
328+ mi := &file_ermite_artifact_proto_msgTypes[3]
329+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
330+ ms.StoreMessageInfo(mi)
331+}
332+
333+func (x *UploadJobArtifactBlockRequest) String() string {
334+ return protoimpl.X.MessageStringOf(x)
335+}
336+
337+func (*UploadJobArtifactBlockRequest) ProtoMessage() {}
338+
339+func (x *UploadJobArtifactBlockRequest) ProtoReflect() protoreflect.Message {
340+ mi := &file_ermite_artifact_proto_msgTypes[3]
341+ if x != nil {
342+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
343+ if ms.LoadMessageInfo() == nil {
344+ ms.StoreMessageInfo(mi)
345+ }
346+ return ms
347+ }
348+ return mi.MessageOf(x)
349+}
350+
351+// Deprecated: Use UploadJobArtifactBlockRequest.ProtoReflect.Descriptor instead.
352+func (*UploadJobArtifactBlockRequest) Descriptor() ([]byte, []int) {
353+ return file_ermite_artifact_proto_rawDescGZIP(), []int{3}
354+}
355+
356+func (x *UploadJobArtifactBlockRequest) GetJobId() string {
357+ if x != nil {
358+ return x.JobId
359+ }
360+ return ""
361+}
362+
363+func (x *UploadJobArtifactBlockRequest) GetArtifactId() int64 {
364+ if x != nil {
365+ return x.ArtifactId
366+ }
367+ return 0
368+}
369+
370+func (x *UploadJobArtifactBlockRequest) GetBlockId() []byte {
371+ if x != nil {
372+ return x.BlockId
373+ }
374+ return nil
375+}
376+
377+func (x *UploadJobArtifactBlockRequest) GetData() []byte {
378+ if x != nil {
379+ return x.Data
380+ }
381+ return nil
382+}
383+
384+// UploadJobArtifactBlockResponse confirms a stored block.
385+type UploadJobArtifactBlockResponse struct {
386+ state protoimpl.MessageState `protogen:"open.v1"`
387+ // Size is the number of bytes of the block as stored.
388+ Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
389+ unknownFields protoimpl.UnknownFields
390+ sizeCache protoimpl.SizeCache
391+}
392+
393+func (x *UploadJobArtifactBlockResponse) Reset() {
394+ *x = UploadJobArtifactBlockResponse{}
395+ mi := &file_ermite_artifact_proto_msgTypes[4]
396+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
397+ ms.StoreMessageInfo(mi)
398+}
399+
400+func (x *UploadJobArtifactBlockResponse) String() string {
401+ return protoimpl.X.MessageStringOf(x)
402+}
403+
404+func (*UploadJobArtifactBlockResponse) ProtoMessage() {}
405+
406+func (x *UploadJobArtifactBlockResponse) ProtoReflect() protoreflect.Message {
407+ mi := &file_ermite_artifact_proto_msgTypes[4]
408+ if x != nil {
409+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
410+ if ms.LoadMessageInfo() == nil {
411+ ms.StoreMessageInfo(mi)
412+ }
413+ return ms
414+ }
415+ return mi.MessageOf(x)
416+}
417+
418+// Deprecated: Use UploadJobArtifactBlockResponse.ProtoReflect.Descriptor instead.
419+func (*UploadJobArtifactBlockResponse) Descriptor() ([]byte, []int) {
420+ return file_ermite_artifact_proto_rawDescGZIP(), []int{4}
421+}
422+
423+func (x *UploadJobArtifactBlockResponse) GetSize() int64 {
424+ if x != nil {
425+ return x.Size
426+ }
427+ return 0
428+}
429+
430+// CommitJobArtifactRequest sets the content of a pending artifact.
431+type CommitJobArtifactRequest struct {
432+ state protoimpl.MessageState `protogen:"open.v1"`
433+ // JobId is the Job.job_id. It must be the job of the token.
434+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
435+ // ArtifactId is the CreateJobArtifactResponse.artifact_id.
436+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
437+ // BlockIds are the blocks of the content, in order, each one as given to
438+ // UploadJobArtifactBlock. At most 50,000; the same id may appear more than
439+ // once.
440+ BlockIds [][]byte `protobuf:"bytes,3,rep,name=block_ids,json=blockIds,proto3" json:"block_ids,omitempty"`
441+ unknownFields protoimpl.UnknownFields
442+ sizeCache protoimpl.SizeCache
443+}
444+
445+func (x *CommitJobArtifactRequest) Reset() {
446+ *x = CommitJobArtifactRequest{}
447+ mi := &file_ermite_artifact_proto_msgTypes[5]
448+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
449+ ms.StoreMessageInfo(mi)
450+}
451+
452+func (x *CommitJobArtifactRequest) String() string {
453+ return protoimpl.X.MessageStringOf(x)
454+}
455+
456+func (*CommitJobArtifactRequest) ProtoMessage() {}
457+
458+func (x *CommitJobArtifactRequest) ProtoReflect() protoreflect.Message {
459+ mi := &file_ermite_artifact_proto_msgTypes[5]
460+ if x != nil {
461+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
462+ if ms.LoadMessageInfo() == nil {
463+ ms.StoreMessageInfo(mi)
464+ }
465+ return ms
466+ }
467+ return mi.MessageOf(x)
468+}
469+
470+// Deprecated: Use CommitJobArtifactRequest.ProtoReflect.Descriptor instead.
471+func (*CommitJobArtifactRequest) Descriptor() ([]byte, []int) {
472+ return file_ermite_artifact_proto_rawDescGZIP(), []int{5}
473+}
474+
475+func (x *CommitJobArtifactRequest) GetJobId() string {
476+ if x != nil {
477+ return x.JobId
478+ }
479+ return ""
480+}
481+
482+func (x *CommitJobArtifactRequest) GetArtifactId() int64 {
483+ if x != nil {
484+ return x.ArtifactId
485+ }
486+ return 0
487+}
488+
489+func (x *CommitJobArtifactRequest) GetBlockIds() [][]byte {
490+ if x != nil {
491+ return x.BlockIds
492+ }
493+ return nil
494+}
495+
496+// CommitJobArtifactResponse describes the committed content.
497+type CommitJobArtifactResponse struct {
498+ state protoimpl.MessageState `protogen:"open.v1"`
499+ // Size is the number of bytes of the content.
500+ Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
501+ // Digest is the SHA-256 of the content, see Artifact.digest.
502+ Digest string `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"`
503+ unknownFields protoimpl.UnknownFields
504+ sizeCache protoimpl.SizeCache
505+}
506+
507+func (x *CommitJobArtifactResponse) Reset() {
508+ *x = CommitJobArtifactResponse{}
509+ mi := &file_ermite_artifact_proto_msgTypes[6]
510+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
511+ ms.StoreMessageInfo(mi)
512+}
513+
514+func (x *CommitJobArtifactResponse) String() string {
515+ return protoimpl.X.MessageStringOf(x)
516+}
517+
518+func (*CommitJobArtifactResponse) ProtoMessage() {}
519+
520+func (x *CommitJobArtifactResponse) ProtoReflect() protoreflect.Message {
521+ mi := &file_ermite_artifact_proto_msgTypes[6]
522+ if x != nil {
523+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
524+ if ms.LoadMessageInfo() == nil {
525+ ms.StoreMessageInfo(mi)
526+ }
527+ return ms
528+ }
529+ return mi.MessageOf(x)
530+}
531+
532+// Deprecated: Use CommitJobArtifactResponse.ProtoReflect.Descriptor instead.
533+func (*CommitJobArtifactResponse) Descriptor() ([]byte, []int) {
534+ return file_ermite_artifact_proto_rawDescGZIP(), []int{6}
535+}
536+
537+func (x *CommitJobArtifactResponse) GetSize() int64 {
538+ if x != nil {
539+ return x.Size
540+ }
541+ return 0
542+}
543+
544+func (x *CommitJobArtifactResponse) GetDigest() string {
545+ if x != nil {
546+ return x.Digest
547+ }
548+ return ""
549+}
550+
551+// FinalizeJobArtifactRequest ends an upload.
552+type FinalizeJobArtifactRequest struct {
553+ state protoimpl.MessageState `protogen:"open.v1"`
554+ // JobId is the Job.job_id. It must be the job of the token.
555+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
556+ // Name is the name given to CreateJobArtifact. The toolkit finalizes by name.
557+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
558+ // Size is the size the uploader counted. Informational: the server keeps the
559+ // size of the content it stored, and only logs a difference.
560+ Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
561+ // Digest is the digest the uploader computed ("sha256:<hex>"), or empty.
562+ // When set it must be the digest of the content.
563+ Digest string `protobuf:"bytes,4,opt,name=digest,proto3" json:"digest,omitempty"`
564+ unknownFields protoimpl.UnknownFields
565+ sizeCache protoimpl.SizeCache
566+}
567+
568+func (x *FinalizeJobArtifactRequest) Reset() {
569+ *x = FinalizeJobArtifactRequest{}
570+ mi := &file_ermite_artifact_proto_msgTypes[7]
571+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
572+ ms.StoreMessageInfo(mi)
573+}
574+
575+func (x *FinalizeJobArtifactRequest) String() string {
576+ return protoimpl.X.MessageStringOf(x)
577+}
578+
579+func (*FinalizeJobArtifactRequest) ProtoMessage() {}
580+
581+func (x *FinalizeJobArtifactRequest) ProtoReflect() protoreflect.Message {
582+ mi := &file_ermite_artifact_proto_msgTypes[7]
583+ if x != nil {
584+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
585+ if ms.LoadMessageInfo() == nil {
586+ ms.StoreMessageInfo(mi)
587+ }
588+ return ms
589+ }
590+ return mi.MessageOf(x)
591+}
592+
593+// Deprecated: Use FinalizeJobArtifactRequest.ProtoReflect.Descriptor instead.
594+func (*FinalizeJobArtifactRequest) Descriptor() ([]byte, []int) {
595+ return file_ermite_artifact_proto_rawDescGZIP(), []int{7}
596+}
597+
598+func (x *FinalizeJobArtifactRequest) GetJobId() string {
599+ if x != nil {
600+ return x.JobId
601+ }
602+ return ""
603+}
604+
605+func (x *FinalizeJobArtifactRequest) GetName() string {
606+ if x != nil {
607+ return x.Name
608+ }
609+ return ""
610+}
611+
612+func (x *FinalizeJobArtifactRequest) GetSize() int64 {
613+ if x != nil {
614+ return x.Size
615+ }
616+ return 0
617+}
618+
619+func (x *FinalizeJobArtifactRequest) GetDigest() string {
620+ if x != nil {
621+ return x.Digest
622+ }
623+ return ""
624+}
625+
626+// FinalizeJobArtifactResponse describes the artifact now visible.
627+type FinalizeJobArtifactResponse struct {
628+ state protoimpl.MessageState `protogen:"open.v1"`
629+ // Artifact is the finalized artifact.
630+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
631+ unknownFields protoimpl.UnknownFields
632+ sizeCache protoimpl.SizeCache
633+}
634+
635+func (x *FinalizeJobArtifactResponse) Reset() {
636+ *x = FinalizeJobArtifactResponse{}
637+ mi := &file_ermite_artifact_proto_msgTypes[8]
638+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
639+ ms.StoreMessageInfo(mi)
640+}
641+
642+func (x *FinalizeJobArtifactResponse) String() string {
643+ return protoimpl.X.MessageStringOf(x)
644+}
645+
646+func (*FinalizeJobArtifactResponse) ProtoMessage() {}
647+
648+func (x *FinalizeJobArtifactResponse) ProtoReflect() protoreflect.Message {
649+ mi := &file_ermite_artifact_proto_msgTypes[8]
650+ if x != nil {
651+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
652+ if ms.LoadMessageInfo() == nil {
653+ ms.StoreMessageInfo(mi)
654+ }
655+ return ms
656+ }
657+ return mi.MessageOf(x)
658+}
659+
660+// Deprecated: Use FinalizeJobArtifactResponse.ProtoReflect.Descriptor instead.
661+func (*FinalizeJobArtifactResponse) Descriptor() ([]byte, []int) {
662+ return file_ermite_artifact_proto_rawDescGZIP(), []int{8}
663+}
664+
665+func (x *FinalizeJobArtifactResponse) GetArtifact() *Artifact {
666+ if x != nil {
667+ return x.Artifact
668+ }
669+ return nil
670+}
671+
672+// ListJobArtifactsRequest selects artifacts of the job's run.
673+type ListJobArtifactsRequest struct {
674+ state protoimpl.MessageState `protogen:"open.v1"`
675+ // JobId is the Job.job_id. It must be the job of the token.
676+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
677+ // Name keeps only the artifact of that name. Empty means every name.
678+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
679+ // ArtifactId keeps only the artifact of that id. 0 means every id.
680+ ArtifactId int64 `protobuf:"varint,3,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
681+ unknownFields protoimpl.UnknownFields
682+ sizeCache protoimpl.SizeCache
683+}
684+
685+func (x *ListJobArtifactsRequest) Reset() {
686+ *x = ListJobArtifactsRequest{}
687+ mi := &file_ermite_artifact_proto_msgTypes[9]
688+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
689+ ms.StoreMessageInfo(mi)
690+}
691+
692+func (x *ListJobArtifactsRequest) String() string {
693+ return protoimpl.X.MessageStringOf(x)
694+}
695+
696+func (*ListJobArtifactsRequest) ProtoMessage() {}
697+
698+func (x *ListJobArtifactsRequest) ProtoReflect() protoreflect.Message {
699+ mi := &file_ermite_artifact_proto_msgTypes[9]
700+ if x != nil {
701+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
702+ if ms.LoadMessageInfo() == nil {
703+ ms.StoreMessageInfo(mi)
704+ }
705+ return ms
706+ }
707+ return mi.MessageOf(x)
708+}
709+
710+// Deprecated: Use ListJobArtifactsRequest.ProtoReflect.Descriptor instead.
711+func (*ListJobArtifactsRequest) Descriptor() ([]byte, []int) {
712+ return file_ermite_artifact_proto_rawDescGZIP(), []int{9}
713+}
714+
715+func (x *ListJobArtifactsRequest) GetJobId() string {
716+ if x != nil {
717+ return x.JobId
718+ }
719+ return ""
720+}
721+
722+func (x *ListJobArtifactsRequest) GetName() string {
723+ if x != nil {
724+ return x.Name
725+ }
726+ return ""
727+}
728+
729+func (x *ListJobArtifactsRequest) GetArtifactId() int64 {
730+ if x != nil {
731+ return x.ArtifactId
732+ }
733+ return 0
734+}
735+
736+// ListJobArtifactsResponse lists artifacts of the job's run.
737+type ListJobArtifactsResponse struct {
738+ state protoimpl.MessageState `protogen:"open.v1"`
739+ // Artifacts are the artifacts, by id.
740+ Artifacts []*Artifact `protobuf:"bytes,1,rep,name=artifacts,proto3" json:"artifacts,omitempty"`
741+ unknownFields protoimpl.UnknownFields
742+ sizeCache protoimpl.SizeCache
743+}
744+
745+func (x *ListJobArtifactsResponse) Reset() {
746+ *x = ListJobArtifactsResponse{}
747+ mi := &file_ermite_artifact_proto_msgTypes[10]
748+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
749+ ms.StoreMessageInfo(mi)
750+}
751+
752+func (x *ListJobArtifactsResponse) String() string {
753+ return protoimpl.X.MessageStringOf(x)
754+}
755+
756+func (*ListJobArtifactsResponse) ProtoMessage() {}
757+
758+func (x *ListJobArtifactsResponse) ProtoReflect() protoreflect.Message {
759+ mi := &file_ermite_artifact_proto_msgTypes[10]
760+ if x != nil {
761+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
762+ if ms.LoadMessageInfo() == nil {
763+ ms.StoreMessageInfo(mi)
764+ }
765+ return ms
766+ }
767+ return mi.MessageOf(x)
768+}
769+
770+// Deprecated: Use ListJobArtifactsResponse.ProtoReflect.Descriptor instead.
771+func (*ListJobArtifactsResponse) Descriptor() ([]byte, []int) {
772+ return file_ermite_artifact_proto_rawDescGZIP(), []int{10}
773+}
774+
775+func (x *ListJobArtifactsResponse) GetArtifacts() []*Artifact {
776+ if x != nil {
777+ return x.Artifacts
778+ }
779+ return nil
780+}
781+
782+// DownloadJobArtifactRequest selects the content of an artifact.
783+type DownloadJobArtifactRequest struct {
784+ state protoimpl.MessageState `protogen:"open.v1"`
785+ // JobId is the Job.job_id. It must be the job of the token.
786+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
787+ // ArtifactId is the Artifact.id of an artifact of the job's run.
788+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
789+ // Offset is the first byte to send, from 0 to the size of the artifact.
790+ Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
791+ unknownFields protoimpl.UnknownFields
792+ sizeCache protoimpl.SizeCache
793+}
794+
795+func (x *DownloadJobArtifactRequest) Reset() {
796+ *x = DownloadJobArtifactRequest{}
797+ mi := &file_ermite_artifact_proto_msgTypes[11]
798+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
799+ ms.StoreMessageInfo(mi)
800+}
801+
802+func (x *DownloadJobArtifactRequest) String() string {
803+ return protoimpl.X.MessageStringOf(x)
804+}
805+
806+func (*DownloadJobArtifactRequest) ProtoMessage() {}
807+
808+func (x *DownloadJobArtifactRequest) ProtoReflect() protoreflect.Message {
809+ mi := &file_ermite_artifact_proto_msgTypes[11]
810+ if x != nil {
811+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
812+ if ms.LoadMessageInfo() == nil {
813+ ms.StoreMessageInfo(mi)
814+ }
815+ return ms
816+ }
817+ return mi.MessageOf(x)
818+}
819+
820+// Deprecated: Use DownloadJobArtifactRequest.ProtoReflect.Descriptor instead.
821+func (*DownloadJobArtifactRequest) Descriptor() ([]byte, []int) {
822+ return file_ermite_artifact_proto_rawDescGZIP(), []int{11}
823+}
824+
825+func (x *DownloadJobArtifactRequest) GetJobId() string {
826+ if x != nil {
827+ return x.JobId
828+ }
829+ return ""
830+}
831+
832+func (x *DownloadJobArtifactRequest) GetArtifactId() int64 {
833+ if x != nil {
834+ return x.ArtifactId
835+ }
836+ return 0
837+}
838+
839+func (x *DownloadJobArtifactRequest) GetOffset() int64 {
840+ if x != nil {
841+ return x.Offset
842+ }
843+ return 0
844+}
845+
846+// DownloadJobArtifactResponse is one message of the content stream.
847+type DownloadJobArtifactResponse struct {
848+ state protoimpl.MessageState `protogen:"open.v1"`
849+ // Artifact describes the artifact. Set in the first message of the stream
850+ // only.
851+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
852+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
853+ // message may have an empty chunk. The chunks of a stream add up to the size
854+ // of the artifact minus the offset.
855+ Chunk []byte `protobuf:"bytes,2,opt,name=chunk,proto3" json:"chunk,omitempty"`
856+ unknownFields protoimpl.UnknownFields
857+ sizeCache protoimpl.SizeCache
858+}
859+
860+func (x *DownloadJobArtifactResponse) Reset() {
861+ *x = DownloadJobArtifactResponse{}
862+ mi := &file_ermite_artifact_proto_msgTypes[12]
863+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
864+ ms.StoreMessageInfo(mi)
865+}
866+
867+func (x *DownloadJobArtifactResponse) String() string {
868+ return protoimpl.X.MessageStringOf(x)
869+}
870+
871+func (*DownloadJobArtifactResponse) ProtoMessage() {}
872+
873+func (x *DownloadJobArtifactResponse) ProtoReflect() protoreflect.Message {
874+ mi := &file_ermite_artifact_proto_msgTypes[12]
875+ if x != nil {
876+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
877+ if ms.LoadMessageInfo() == nil {
878+ ms.StoreMessageInfo(mi)
879+ }
880+ return ms
881+ }
882+ return mi.MessageOf(x)
883+}
884+
885+// Deprecated: Use DownloadJobArtifactResponse.ProtoReflect.Descriptor instead.
886+func (*DownloadJobArtifactResponse) Descriptor() ([]byte, []int) {
887+ return file_ermite_artifact_proto_rawDescGZIP(), []int{12}
888+}
889+
890+func (x *DownloadJobArtifactResponse) GetArtifact() *Artifact {
891+ if x != nil {
892+ return x.Artifact
893+ }
894+ return nil
895+}
896+
897+func (x *DownloadJobArtifactResponse) GetChunk() []byte {
898+ if x != nil {
899+ return x.Chunk
900+ }
901+ return nil
902+}
903+
904+// DeleteJobArtifactRequest names the artifact to delete.
905+type DeleteJobArtifactRequest struct {
906+ state protoimpl.MessageState `protogen:"open.v1"`
907+ // JobId is the Job.job_id. It must be the job of the token.
908+ JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
909+ // Name is the name of a finalized artifact of the job's run.
910+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
911+ unknownFields protoimpl.UnknownFields
912+ sizeCache protoimpl.SizeCache
913+}
914+
915+func (x *DeleteJobArtifactRequest) Reset() {
916+ *x = DeleteJobArtifactRequest{}
917+ mi := &file_ermite_artifact_proto_msgTypes[13]
918+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
919+ ms.StoreMessageInfo(mi)
920+}
921+
922+func (x *DeleteJobArtifactRequest) String() string {
923+ return protoimpl.X.MessageStringOf(x)
924+}
925+
926+func (*DeleteJobArtifactRequest) ProtoMessage() {}
927+
928+func (x *DeleteJobArtifactRequest) ProtoReflect() protoreflect.Message {
929+ mi := &file_ermite_artifact_proto_msgTypes[13]
930+ if x != nil {
931+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
932+ if ms.LoadMessageInfo() == nil {
933+ ms.StoreMessageInfo(mi)
934+ }
935+ return ms
936+ }
937+ return mi.MessageOf(x)
938+}
939+
940+// Deprecated: Use DeleteJobArtifactRequest.ProtoReflect.Descriptor instead.
941+func (*DeleteJobArtifactRequest) Descriptor() ([]byte, []int) {
942+ return file_ermite_artifact_proto_rawDescGZIP(), []int{13}
943+}
944+
945+func (x *DeleteJobArtifactRequest) GetJobId() string {
946+ if x != nil {
947+ return x.JobId
948+ }
949+ return ""
950+}
951+
952+func (x *DeleteJobArtifactRequest) GetName() string {
953+ if x != nil {
954+ return x.Name
955+ }
956+ return ""
957+}
958+
959+// DeleteJobArtifactResponse identifies the deleted artifact.
960+type DeleteJobArtifactResponse struct {
961+ state protoimpl.MessageState `protogen:"open.v1"`
962+ // ArtifactId is the Artifact.id of the artifact that was deleted.
963+ ArtifactId int64 `protobuf:"varint,1,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
964+ unknownFields protoimpl.UnknownFields
965+ sizeCache protoimpl.SizeCache
966+}
967+
968+func (x *DeleteJobArtifactResponse) Reset() {
969+ *x = DeleteJobArtifactResponse{}
970+ mi := &file_ermite_artifact_proto_msgTypes[14]
971+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
972+ ms.StoreMessageInfo(mi)
973+}
974+
975+func (x *DeleteJobArtifactResponse) String() string {
976+ return protoimpl.X.MessageStringOf(x)
977+}
978+
979+func (*DeleteJobArtifactResponse) ProtoMessage() {}
980+
981+func (x *DeleteJobArtifactResponse) ProtoReflect() protoreflect.Message {
982+ mi := &file_ermite_artifact_proto_msgTypes[14]
983+ if x != nil {
984+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
985+ if ms.LoadMessageInfo() == nil {
986+ ms.StoreMessageInfo(mi)
987+ }
988+ return ms
989+ }
990+ return mi.MessageOf(x)
991+}
992+
993+// Deprecated: Use DeleteJobArtifactResponse.ProtoReflect.Descriptor instead.
994+func (*DeleteJobArtifactResponse) Descriptor() ([]byte, []int) {
995+ return file_ermite_artifact_proto_rawDescGZIP(), []int{14}
996+}
997+
998+func (x *DeleteJobArtifactResponse) GetArtifactId() int64 {
999+ if x != nil {
1000+ return x.ArtifactId
1001+ }
1002+ return 0
1003+}
1004+
1005+// ListArtifactsRequest selects the artifacts of a run.
1006+type ListArtifactsRequest struct {
1007+ state protoimpl.MessageState `protogen:"open.v1"`
1008+ // Repo is the repository name.
1009+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1010+ // RunId is the run.
1011+ RunId int64 `protobuf:"varint,2,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"`
1012+ unknownFields protoimpl.UnknownFields
1013+ sizeCache protoimpl.SizeCache
1014+}
1015+
1016+func (x *ListArtifactsRequest) Reset() {
1017+ *x = ListArtifactsRequest{}
1018+ mi := &file_ermite_artifact_proto_msgTypes[15]
1019+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1020+ ms.StoreMessageInfo(mi)
1021+}
1022+
1023+func (x *ListArtifactsRequest) String() string {
1024+ return protoimpl.X.MessageStringOf(x)
1025+}
1026+
1027+func (*ListArtifactsRequest) ProtoMessage() {}
1028+
1029+func (x *ListArtifactsRequest) ProtoReflect() protoreflect.Message {
1030+ mi := &file_ermite_artifact_proto_msgTypes[15]
1031+ if x != nil {
1032+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1033+ if ms.LoadMessageInfo() == nil {
1034+ ms.StoreMessageInfo(mi)
1035+ }
1036+ return ms
1037+ }
1038+ return mi.MessageOf(x)
1039+}
1040+
1041+// Deprecated: Use ListArtifactsRequest.ProtoReflect.Descriptor instead.
1042+func (*ListArtifactsRequest) Descriptor() ([]byte, []int) {
1043+ return file_ermite_artifact_proto_rawDescGZIP(), []int{15}
1044+}
1045+
1046+func (x *ListArtifactsRequest) GetRepo() string {
1047+ if x != nil {
1048+ return x.Repo
1049+ }
1050+ return ""
1051+}
1052+
1053+func (x *ListArtifactsRequest) GetRunId() int64 {
1054+ if x != nil {
1055+ return x.RunId
1056+ }
1057+ return 0
1058+}
1059+
1060+// ListArtifactsResponse lists the artifacts of a run.
1061+type ListArtifactsResponse struct {
1062+ state protoimpl.MessageState `protogen:"open.v1"`
1063+ // Artifacts are the artifacts of the run, all attempts, by id.
1064+ Artifacts []*Artifact `protobuf:"bytes,1,rep,name=artifacts,proto3" json:"artifacts,omitempty"`
1065+ // UsedBytes is the space that all the artifacts of the repository use,
1066+ // uploads in progress included.
1067+ UsedBytes int64 `protobuf:"varint,2,opt,name=used_bytes,json=usedBytes,proto3" json:"used_bytes,omitempty"`
1068+ // QuotaBytes is the space the artifacts of the repository may use.
1069+ QuotaBytes int64 `protobuf:"varint,3,opt,name=quota_bytes,json=quotaBytes,proto3" json:"quota_bytes,omitempty"`
1070+ unknownFields protoimpl.UnknownFields
1071+ sizeCache protoimpl.SizeCache
1072+}
1073+
1074+func (x *ListArtifactsResponse) Reset() {
1075+ *x = ListArtifactsResponse{}
1076+ mi := &file_ermite_artifact_proto_msgTypes[16]
1077+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1078+ ms.StoreMessageInfo(mi)
1079+}
1080+
1081+func (x *ListArtifactsResponse) String() string {
1082+ return protoimpl.X.MessageStringOf(x)
1083+}
1084+
1085+func (*ListArtifactsResponse) ProtoMessage() {}
1086+
1087+func (x *ListArtifactsResponse) ProtoReflect() protoreflect.Message {
1088+ mi := &file_ermite_artifact_proto_msgTypes[16]
1089+ if x != nil {
1090+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1091+ if ms.LoadMessageInfo() == nil {
1092+ ms.StoreMessageInfo(mi)
1093+ }
1094+ return ms
1095+ }
1096+ return mi.MessageOf(x)
1097+}
1098+
1099+// Deprecated: Use ListArtifactsResponse.ProtoReflect.Descriptor instead.
1100+func (*ListArtifactsResponse) Descriptor() ([]byte, []int) {
1101+ return file_ermite_artifact_proto_rawDescGZIP(), []int{16}
1102+}
1103+
1104+func (x *ListArtifactsResponse) GetArtifacts() []*Artifact {
1105+ if x != nil {
1106+ return x.Artifacts
1107+ }
1108+ return nil
1109+}
1110+
1111+func (x *ListArtifactsResponse) GetUsedBytes() int64 {
1112+ if x != nil {
1113+ return x.UsedBytes
1114+ }
1115+ return 0
1116+}
1117+
1118+func (x *ListArtifactsResponse) GetQuotaBytes() int64 {
1119+ if x != nil {
1120+ return x.QuotaBytes
1121+ }
1122+ return 0
1123+}
1124+
1125+// DownloadArtifactRequest selects the content of an artifact.
1126+type DownloadArtifactRequest struct {
1127+ state protoimpl.MessageState `protogen:"open.v1"`
1128+ // Repo is the repository name.
1129+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1130+ // ArtifactId is the Artifact.id.
1131+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
1132+ // Offset is the first byte to send, from 0 to the size of the artifact.
1133+ Offset int64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"`
1134+ unknownFields protoimpl.UnknownFields
1135+ sizeCache protoimpl.SizeCache
1136+}
1137+
1138+func (x *DownloadArtifactRequest) Reset() {
1139+ *x = DownloadArtifactRequest{}
1140+ mi := &file_ermite_artifact_proto_msgTypes[17]
1141+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1142+ ms.StoreMessageInfo(mi)
1143+}
1144+
1145+func (x *DownloadArtifactRequest) String() string {
1146+ return protoimpl.X.MessageStringOf(x)
1147+}
1148+
1149+func (*DownloadArtifactRequest) ProtoMessage() {}
1150+
1151+func (x *DownloadArtifactRequest) ProtoReflect() protoreflect.Message {
1152+ mi := &file_ermite_artifact_proto_msgTypes[17]
1153+ if x != nil {
1154+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1155+ if ms.LoadMessageInfo() == nil {
1156+ ms.StoreMessageInfo(mi)
1157+ }
1158+ return ms
1159+ }
1160+ return mi.MessageOf(x)
1161+}
1162+
1163+// Deprecated: Use DownloadArtifactRequest.ProtoReflect.Descriptor instead.
1164+func (*DownloadArtifactRequest) Descriptor() ([]byte, []int) {
1165+ return file_ermite_artifact_proto_rawDescGZIP(), []int{17}
1166+}
1167+
1168+func (x *DownloadArtifactRequest) GetRepo() string {
1169+ if x != nil {
1170+ return x.Repo
1171+ }
1172+ return ""
1173+}
1174+
1175+func (x *DownloadArtifactRequest) GetArtifactId() int64 {
1176+ if x != nil {
1177+ return x.ArtifactId
1178+ }
1179+ return 0
1180+}
1181+
1182+func (x *DownloadArtifactRequest) GetOffset() int64 {
1183+ if x != nil {
1184+ return x.Offset
1185+ }
1186+ return 0
1187+}
1188+
1189+// DownloadArtifactResponse is one message of the content stream.
1190+type DownloadArtifactResponse struct {
1191+ state protoimpl.MessageState `protogen:"open.v1"`
1192+ // Artifact describes the artifact. Set in the first message of the stream
1193+ // only.
1194+ Artifact *Artifact `protobuf:"bytes,1,opt,name=artifact,proto3" json:"artifact,omitempty"`
1195+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
1196+ // message may have an empty chunk.
1197+ Chunk []byte `protobuf:"bytes,2,opt,name=chunk,proto3" json:"chunk,omitempty"`
1198+ unknownFields protoimpl.UnknownFields
1199+ sizeCache protoimpl.SizeCache
1200+}
1201+
1202+func (x *DownloadArtifactResponse) Reset() {
1203+ *x = DownloadArtifactResponse{}
1204+ mi := &file_ermite_artifact_proto_msgTypes[18]
1205+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1206+ ms.StoreMessageInfo(mi)
1207+}
1208+
1209+func (x *DownloadArtifactResponse) String() string {
1210+ return protoimpl.X.MessageStringOf(x)
1211+}
1212+
1213+func (*DownloadArtifactResponse) ProtoMessage() {}
1214+
1215+func (x *DownloadArtifactResponse) ProtoReflect() protoreflect.Message {
1216+ mi := &file_ermite_artifact_proto_msgTypes[18]
1217+ if x != nil {
1218+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1219+ if ms.LoadMessageInfo() == nil {
1220+ ms.StoreMessageInfo(mi)
1221+ }
1222+ return ms
1223+ }
1224+ return mi.MessageOf(x)
1225+}
1226+
1227+// Deprecated: Use DownloadArtifactResponse.ProtoReflect.Descriptor instead.
1228+func (*DownloadArtifactResponse) Descriptor() ([]byte, []int) {
1229+ return file_ermite_artifact_proto_rawDescGZIP(), []int{18}
1230+}
1231+
1232+func (x *DownloadArtifactResponse) GetArtifact() *Artifact {
1233+ if x != nil {
1234+ return x.Artifact
1235+ }
1236+ return nil
1237+}
1238+
1239+func (x *DownloadArtifactResponse) GetChunk() []byte {
1240+ if x != nil {
1241+ return x.Chunk
1242+ }
1243+ return nil
1244+}
1245+
1246+// DeleteArtifactRequest names the artifact to delete.
1247+type DeleteArtifactRequest struct {
1248+ state protoimpl.MessageState `protogen:"open.v1"`
1249+ // Repo is the repository name.
1250+ Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
1251+ // ArtifactId is the Artifact.id.
1252+ ArtifactId int64 `protobuf:"varint,2,opt,name=artifact_id,json=artifactId,proto3" json:"artifact_id,omitempty"`
1253+ unknownFields protoimpl.UnknownFields
1254+ sizeCache protoimpl.SizeCache
1255+}
1256+
1257+func (x *DeleteArtifactRequest) Reset() {
1258+ *x = DeleteArtifactRequest{}
1259+ mi := &file_ermite_artifact_proto_msgTypes[19]
1260+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1261+ ms.StoreMessageInfo(mi)
1262+}
1263+
1264+func (x *DeleteArtifactRequest) String() string {
1265+ return protoimpl.X.MessageStringOf(x)
1266+}
1267+
1268+func (*DeleteArtifactRequest) ProtoMessage() {}
1269+
1270+func (x *DeleteArtifactRequest) ProtoReflect() protoreflect.Message {
1271+ mi := &file_ermite_artifact_proto_msgTypes[19]
1272+ if x != nil {
1273+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1274+ if ms.LoadMessageInfo() == nil {
1275+ ms.StoreMessageInfo(mi)
1276+ }
1277+ return ms
1278+ }
1279+ return mi.MessageOf(x)
1280+}
1281+
1282+// Deprecated: Use DeleteArtifactRequest.ProtoReflect.Descriptor instead.
1283+func (*DeleteArtifactRequest) Descriptor() ([]byte, []int) {
1284+ return file_ermite_artifact_proto_rawDescGZIP(), []int{19}
1285+}
1286+
1287+func (x *DeleteArtifactRequest) GetRepo() string {
1288+ if x != nil {
1289+ return x.Repo
1290+ }
1291+ return ""
1292+}
1293+
1294+func (x *DeleteArtifactRequest) GetArtifactId() int64 {
1295+ if x != nil {
1296+ return x.ArtifactId
1297+ }
1298+ return 0
1299+}
1300+
1301+// DeleteArtifactResponse is empty.
1302+type DeleteArtifactResponse struct {
1303+ state protoimpl.MessageState `protogen:"open.v1"`
1304+ unknownFields protoimpl.UnknownFields
1305+ sizeCache protoimpl.SizeCache
1306+}
1307+
1308+func (x *DeleteArtifactResponse) Reset() {
1309+ *x = DeleteArtifactResponse{}
1310+ mi := &file_ermite_artifact_proto_msgTypes[20]
1311+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1312+ ms.StoreMessageInfo(mi)
1313+}
1314+
1315+func (x *DeleteArtifactResponse) String() string {
1316+ return protoimpl.X.MessageStringOf(x)
1317+}
1318+
1319+func (*DeleteArtifactResponse) ProtoMessage() {}
1320+
1321+func (x *DeleteArtifactResponse) ProtoReflect() protoreflect.Message {
1322+ mi := &file_ermite_artifact_proto_msgTypes[20]
1323+ if x != nil {
1324+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
1325+ if ms.LoadMessageInfo() == nil {
1326+ ms.StoreMessageInfo(mi)
1327+ }
1328+ return ms
1329+ }
1330+ return mi.MessageOf(x)
1331+}
1332+
1333+// Deprecated: Use DeleteArtifactResponse.ProtoReflect.Descriptor instead.
1334+func (*DeleteArtifactResponse) Descriptor() ([]byte, []int) {
1335+ return file_ermite_artifact_proto_rawDescGZIP(), []int{20}
1336+}
1337+
1338+var File_ermite_artifact_proto protoreflect.FileDescriptor
1339+
1340+const file_ermite_artifact_proto_rawDesc = "" +
1341+ "\n" +
1342+ "\x15ermite/artifact.proto\x12\x06ermite\x1a\x1fgoogle/protobuf/timestamp.proto\"\xcb\x02\n" +
1343+ "\bArtifact\x12\x0e\n" +
1344+ "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" +
1345+ "\x04repo\x18\x02 \x01(\tR\x04repo\x12\x15\n" +
1346+ "\x06run_id\x18\x03 \x01(\x03R\x05runId\x12\x18\n" +
1347+ "\aattempt\x18\x04 \x01(\x05R\aattempt\x12\x15\n" +
1348+ "\x06job_id\x18\x05 \x01(\tR\x05jobId\x12\x12\n" +
1349+ "\x04name\x18\x06 \x01(\tR\x04name\x12\x12\n" +
1350+ "\x04size\x18\a \x01(\x03R\x04size\x12\x16\n" +
1351+ "\x06digest\x18\b \x01(\tR\x06digest\x12\x1d\n" +
1352+ "\n" +
1353+ "media_type\x18\t \x01(\tR\tmediaType\x129\n" +
1354+ "\n" +
1355+ "created_at\x18\n" +
1356+ " \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x129\n" +
1357+ "\n" +
1358+ "expires_at\x18\v \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"\x9f\x01\n" +
1359+ "\x18CreateJobArtifactRequest\x12\x15\n" +
1360+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1361+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x1d\n" +
1362+ "\n" +
1363+ "media_type\x18\x03 \x01(\tR\tmediaType\x129\n" +
1364+ "\n" +
1365+ "expires_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"w\n" +
1366+ "\x19CreateJobArtifactResponse\x12\x1f\n" +
1367+ "\vartifact_id\x18\x01 \x01(\x03R\n" +
1368+ "artifactId\x129\n" +
1369+ "\n" +
1370+ "expires_at\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\texpiresAt\"\x86\x01\n" +
1371+ "\x1dUploadJobArtifactBlockRequest\x12\x15\n" +
1372+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1373+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1374+ "artifactId\x12\x19\n" +
1375+ "\bblock_id\x18\x03 \x01(\fR\ablockId\x12\x12\n" +
1376+ "\x04data\x18\x04 \x01(\fR\x04data\"4\n" +
1377+ "\x1eUploadJobArtifactBlockResponse\x12\x12\n" +
1378+ "\x04size\x18\x01 \x01(\x03R\x04size\"o\n" +
1379+ "\x18CommitJobArtifactRequest\x12\x15\n" +
1380+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1381+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1382+ "artifactId\x12\x1b\n" +
1383+ "\tblock_ids\x18\x03 \x03(\fR\bblockIds\"G\n" +
1384+ "\x19CommitJobArtifactResponse\x12\x12\n" +
1385+ "\x04size\x18\x01 \x01(\x03R\x04size\x12\x16\n" +
1386+ "\x06digest\x18\x02 \x01(\tR\x06digest\"s\n" +
1387+ "\x1aFinalizeJobArtifactRequest\x12\x15\n" +
1388+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1389+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
1390+ "\x04size\x18\x03 \x01(\x03R\x04size\x12\x16\n" +
1391+ "\x06digest\x18\x04 \x01(\tR\x06digest\"K\n" +
1392+ "\x1bFinalizeJobArtifactResponse\x12,\n" +
1393+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\"e\n" +
1394+ "\x17ListJobArtifactsRequest\x12\x15\n" +
1395+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1396+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x1f\n" +
1397+ "\vartifact_id\x18\x03 \x01(\x03R\n" +
1398+ "artifactId\"J\n" +
1399+ "\x18ListJobArtifactsResponse\x12.\n" +
1400+ "\tartifacts\x18\x01 \x03(\v2\x10.ermite.ArtifactR\tartifacts\"l\n" +
1401+ "\x1aDownloadJobArtifactRequest\x12\x15\n" +
1402+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x1f\n" +
1403+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1404+ "artifactId\x12\x16\n" +
1405+ "\x06offset\x18\x03 \x01(\x03R\x06offset\"a\n" +
1406+ "\x1bDownloadJobArtifactResponse\x12,\n" +
1407+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\x12\x14\n" +
1408+ "\x05chunk\x18\x02 \x01(\fR\x05chunk\"E\n" +
1409+ "\x18DeleteJobArtifactRequest\x12\x15\n" +
1410+ "\x06job_id\x18\x01 \x01(\tR\x05jobId\x12\x12\n" +
1411+ "\x04name\x18\x02 \x01(\tR\x04name\"<\n" +
1412+ "\x19DeleteJobArtifactResponse\x12\x1f\n" +
1413+ "\vartifact_id\x18\x01 \x01(\x03R\n" +
1414+ "artifactId\"A\n" +
1415+ "\x14ListArtifactsRequest\x12\x12\n" +
1416+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x15\n" +
1417+ "\x06run_id\x18\x02 \x01(\x03R\x05runId\"\x87\x01\n" +
1418+ "\x15ListArtifactsResponse\x12.\n" +
1419+ "\tartifacts\x18\x01 \x03(\v2\x10.ermite.ArtifactR\tartifacts\x12\x1d\n" +
1420+ "\n" +
1421+ "used_bytes\x18\x02 \x01(\x03R\tusedBytes\x12\x1f\n" +
1422+ "\vquota_bytes\x18\x03 \x01(\x03R\n" +
1423+ "quotaBytes\"f\n" +
1424+ "\x17DownloadArtifactRequest\x12\x12\n" +
1425+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x1f\n" +
1426+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1427+ "artifactId\x12\x16\n" +
1428+ "\x06offset\x18\x03 \x01(\x03R\x06offset\"^\n" +
1429+ "\x18DownloadArtifactResponse\x12,\n" +
1430+ "\bartifact\x18\x01 \x01(\v2\x10.ermite.ArtifactR\bartifact\x12\x14\n" +
1431+ "\x05chunk\x18\x02 \x01(\fR\x05chunk\"L\n" +
1432+ "\x15DeleteArtifactRequest\x12\x12\n" +
1433+ "\x04repo\x18\x01 \x01(\tR\x04repo\x12\x1f\n" +
1434+ "\vartifact_id\x18\x02 \x01(\x03R\n" +
1435+ "artifactId\"\x18\n" +
1436+ "\x16DeleteArtifactResponse2\xa6\x05\n" +
1437+ "\x12JobArtifactService\x12X\n" +
1438+ "\x11CreateJobArtifact\x12 .ermite.CreateJobArtifactRequest\x1a!.ermite.CreateJobArtifactResponse\x12i\n" +
1439+ "\x16UploadJobArtifactBlock\x12%.ermite.UploadJobArtifactBlockRequest\x1a&.ermite.UploadJobArtifactBlockResponse(\x01\x12X\n" +
1440+ "\x11CommitJobArtifact\x12 .ermite.CommitJobArtifactRequest\x1a!.ermite.CommitJobArtifactResponse\x12^\n" +
1441+ "\x13FinalizeJobArtifact\x12\".ermite.FinalizeJobArtifactRequest\x1a#.ermite.FinalizeJobArtifactResponse\x12U\n" +
1442+ "\x10ListJobArtifacts\x12\x1f.ermite.ListJobArtifactsRequest\x1a .ermite.ListJobArtifactsResponse\x12`\n" +
1443+ "\x13DownloadJobArtifact\x12\".ermite.DownloadJobArtifactRequest\x1a#.ermite.DownloadJobArtifactResponse0\x01\x12X\n" +
1444+ "\x11DeleteJobArtifact\x12 .ermite.DeleteJobArtifactRequest\x1a!.ermite.DeleteJobArtifactResponse2\x89\x02\n" +
1445+ "\x0fArtifactService\x12L\n" +
1446+ "\rListArtifacts\x12\x1c.ermite.ListArtifactsRequest\x1a\x1d.ermite.ListArtifactsResponse\x12W\n" +
1447+ "\x10DownloadArtifact\x12\x1f.ermite.DownloadArtifactRequest\x1a .ermite.DownloadArtifactResponse0\x01\x12O\n" +
1448+ "\x0eDeleteArtifact\x12\x1d.ermite.DeleteArtifactRequest\x1a\x1e.ermite.DeleteArtifactResponseBt\n" +
1449+ "\n" +
1450+ "com.ermiteB\rArtifactProtoP\x01Z\x1fbnema.dev/ermite-api/gen/ermite\xa2\x02\x03EXX\xaa\x02\x06Ermite\xca\x02\x06Ermite\xe2\x02\x12Ermite\\GPBMetadata\xea\x02\x06Ermiteb\x06proto3"
1451+
1452+var (
1453+ file_ermite_artifact_proto_rawDescOnce sync.Once
1454+ file_ermite_artifact_proto_rawDescData []byte
1455+)
1456+
1457+func file_ermite_artifact_proto_rawDescGZIP() []byte {
1458+ file_ermite_artifact_proto_rawDescOnce.Do(func() {
1459+ file_ermite_artifact_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ermite_artifact_proto_rawDesc), len(file_ermite_artifact_proto_rawDesc)))
1460+ })
1461+ return file_ermite_artifact_proto_rawDescData
1462+}
1463+
1464+var file_ermite_artifact_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
1465+var file_ermite_artifact_proto_goTypes = []any{
1466+ (*Artifact)(nil), // 0: ermite.Artifact
1467+ (*CreateJobArtifactRequest)(nil), // 1: ermite.CreateJobArtifactRequest
1468+ (*CreateJobArtifactResponse)(nil), // 2: ermite.CreateJobArtifactResponse
1469+ (*UploadJobArtifactBlockRequest)(nil), // 3: ermite.UploadJobArtifactBlockRequest
1470+ (*UploadJobArtifactBlockResponse)(nil), // 4: ermite.UploadJobArtifactBlockResponse
1471+ (*CommitJobArtifactRequest)(nil), // 5: ermite.CommitJobArtifactRequest
1472+ (*CommitJobArtifactResponse)(nil), // 6: ermite.CommitJobArtifactResponse
1473+ (*FinalizeJobArtifactRequest)(nil), // 7: ermite.FinalizeJobArtifactRequest
1474+ (*FinalizeJobArtifactResponse)(nil), // 8: ermite.FinalizeJobArtifactResponse
1475+ (*ListJobArtifactsRequest)(nil), // 9: ermite.ListJobArtifactsRequest
1476+ (*ListJobArtifactsResponse)(nil), // 10: ermite.ListJobArtifactsResponse
1477+ (*DownloadJobArtifactRequest)(nil), // 11: ermite.DownloadJobArtifactRequest
1478+ (*DownloadJobArtifactResponse)(nil), // 12: ermite.DownloadJobArtifactResponse
1479+ (*DeleteJobArtifactRequest)(nil), // 13: ermite.DeleteJobArtifactRequest
1480+ (*DeleteJobArtifactResponse)(nil), // 14: ermite.DeleteJobArtifactResponse
1481+ (*ListArtifactsRequest)(nil), // 15: ermite.ListArtifactsRequest
1482+ (*ListArtifactsResponse)(nil), // 16: ermite.ListArtifactsResponse
1483+ (*DownloadArtifactRequest)(nil), // 17: ermite.DownloadArtifactRequest
1484+ (*DownloadArtifactResponse)(nil), // 18: ermite.DownloadArtifactResponse
1485+ (*DeleteArtifactRequest)(nil), // 19: ermite.DeleteArtifactRequest
1486+ (*DeleteArtifactResponse)(nil), // 20: ermite.DeleteArtifactResponse
1487+ (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp
1488+}
1489+var file_ermite_artifact_proto_depIdxs = []int32{
1490+ 21, // 0: ermite.Artifact.created_at:type_name -> google.protobuf.Timestamp
1491+ 21, // 1: ermite.Artifact.expires_at:type_name -> google.protobuf.Timestamp
1492+ 21, // 2: ermite.CreateJobArtifactRequest.expires_at:type_name -> google.protobuf.Timestamp
1493+ 21, // 3: ermite.CreateJobArtifactResponse.expires_at:type_name -> google.protobuf.Timestamp
1494+ 0, // 4: ermite.FinalizeJobArtifactResponse.artifact:type_name -> ermite.Artifact
1495+ 0, // 5: ermite.ListJobArtifactsResponse.artifacts:type_name -> ermite.Artifact
1496+ 0, // 6: ermite.DownloadJobArtifactResponse.artifact:type_name -> ermite.Artifact
1497+ 0, // 7: ermite.ListArtifactsResponse.artifacts:type_name -> ermite.Artifact
1498+ 0, // 8: ermite.DownloadArtifactResponse.artifact:type_name -> ermite.Artifact
1499+ 1, // 9: ermite.JobArtifactService.CreateJobArtifact:input_type -> ermite.CreateJobArtifactRequest
1500+ 3, // 10: ermite.JobArtifactService.UploadJobArtifactBlock:input_type -> ermite.UploadJobArtifactBlockRequest
1501+ 5, // 11: ermite.JobArtifactService.CommitJobArtifact:input_type -> ermite.CommitJobArtifactRequest
1502+ 7, // 12: ermite.JobArtifactService.FinalizeJobArtifact:input_type -> ermite.FinalizeJobArtifactRequest
1503+ 9, // 13: ermite.JobArtifactService.ListJobArtifacts:input_type -> ermite.ListJobArtifactsRequest
1504+ 11, // 14: ermite.JobArtifactService.DownloadJobArtifact:input_type -> ermite.DownloadJobArtifactRequest
1505+ 13, // 15: ermite.JobArtifactService.DeleteJobArtifact:input_type -> ermite.DeleteJobArtifactRequest
1506+ 15, // 16: ermite.ArtifactService.ListArtifacts:input_type -> ermite.ListArtifactsRequest
1507+ 17, // 17: ermite.ArtifactService.DownloadArtifact:input_type -> ermite.DownloadArtifactRequest
1508+ 19, // 18: ermite.ArtifactService.DeleteArtifact:input_type -> ermite.DeleteArtifactRequest
1509+ 2, // 19: ermite.JobArtifactService.CreateJobArtifact:output_type -> ermite.CreateJobArtifactResponse
1510+ 4, // 20: ermite.JobArtifactService.UploadJobArtifactBlock:output_type -> ermite.UploadJobArtifactBlockResponse
1511+ 6, // 21: ermite.JobArtifactService.CommitJobArtifact:output_type -> ermite.CommitJobArtifactResponse
1512+ 8, // 22: ermite.JobArtifactService.FinalizeJobArtifact:output_type -> ermite.FinalizeJobArtifactResponse
1513+ 10, // 23: ermite.JobArtifactService.ListJobArtifacts:output_type -> ermite.ListJobArtifactsResponse
1514+ 12, // 24: ermite.JobArtifactService.DownloadJobArtifact:output_type -> ermite.DownloadJobArtifactResponse
1515+ 14, // 25: ermite.JobArtifactService.DeleteJobArtifact:output_type -> ermite.DeleteJobArtifactResponse
1516+ 16, // 26: ermite.ArtifactService.ListArtifacts:output_type -> ermite.ListArtifactsResponse
1517+ 18, // 27: ermite.ArtifactService.DownloadArtifact:output_type -> ermite.DownloadArtifactResponse
1518+ 20, // 28: ermite.ArtifactService.DeleteArtifact:output_type -> ermite.DeleteArtifactResponse
1519+ 19, // [19:29] is the sub-list for method output_type
1520+ 9, // [9:19] is the sub-list for method input_type
1521+ 9, // [9:9] is the sub-list for extension type_name
1522+ 9, // [9:9] is the sub-list for extension extendee
1523+ 0, // [0:9] is the sub-list for field type_name
1524+}
1525+
1526+func init() { file_ermite_artifact_proto_init() }
1527+func file_ermite_artifact_proto_init() {
1528+ if File_ermite_artifact_proto != nil {
1529+ return
1530+ }
1531+ type x struct{}
1532+ out := protoimpl.TypeBuilder{
1533+ File: protoimpl.DescBuilder{
1534+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
1535+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_ermite_artifact_proto_rawDesc), len(file_ermite_artifact_proto_rawDesc)),
1536+ NumEnums: 0,
1537+ NumMessages: 21,
1538+ NumExtensions: 0,
1539+ NumServices: 2,
1540+ },
1541+ GoTypes: file_ermite_artifact_proto_goTypes,
1542+ DependencyIndexes: file_ermite_artifact_proto_depIdxs,
1543+ MessageInfos: file_ermite_artifact_proto_msgTypes,
1544+ }.Build()
1545+ File_ermite_artifact_proto = out.File
1546+ file_ermite_artifact_proto_goTypes = nil
1547+ file_ermite_artifact_proto_depIdxs = nil
1548+}
A gen/ermite/ermiteconnect/artifact.connect.go +530 -0
@@ -0,0 +1,530 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/artifact.proto
6+
7+package ermiteconnect
8+
9+import (
10+ ermite "bnema.dev/ermite-api/gen/ermite"
11+ connect "connectrpc.com/connect"
12+ context "context"
13+ errors "errors"
14+ http "net/http"
15+ strings "strings"
16+)
17+
18+// This is a compile-time assertion to ensure that this generated file and the connect package are
19+// compatible. If you get a compiler error that this constant is not defined, this code was
20+// generated with a version of connect newer than the one compiled into your binary. You can fix the
21+// problem by either regenerating this code with an older version of connect or updating the connect
22+// version compiled into your binary.
23+const _ = connect.IsAtLeastVersion1_13_0
24+
25+const (
26+ // JobArtifactServiceName is the fully-qualified name of the JobArtifactService service.
27+ JobArtifactServiceName = "ermite.JobArtifactService"
28+ // ArtifactServiceName is the fully-qualified name of the ArtifactService service.
29+ ArtifactServiceName = "ermite.ArtifactService"
30+)
31+
32+// These constants are the fully-qualified names of the RPCs defined in this package. They're
33+// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
34+//
35+// Note that these are different from the fully-qualified method names used by
36+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
37+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
38+// period.
39+const (
40+ // JobArtifactServiceCreateJobArtifactProcedure is the fully-qualified name of the
41+ // JobArtifactService's CreateJobArtifact RPC.
42+ JobArtifactServiceCreateJobArtifactProcedure = "/ermite.JobArtifactService/CreateJobArtifact"
43+ // JobArtifactServiceUploadJobArtifactBlockProcedure is the fully-qualified name of the
44+ // JobArtifactService's UploadJobArtifactBlock RPC.
45+ JobArtifactServiceUploadJobArtifactBlockProcedure = "/ermite.JobArtifactService/UploadJobArtifactBlock"
46+ // JobArtifactServiceCommitJobArtifactProcedure is the fully-qualified name of the
47+ // JobArtifactService's CommitJobArtifact RPC.
48+ JobArtifactServiceCommitJobArtifactProcedure = "/ermite.JobArtifactService/CommitJobArtifact"
49+ // JobArtifactServiceFinalizeJobArtifactProcedure is the fully-qualified name of the
50+ // JobArtifactService's FinalizeJobArtifact RPC.
51+ JobArtifactServiceFinalizeJobArtifactProcedure = "/ermite.JobArtifactService/FinalizeJobArtifact"
52+ // JobArtifactServiceListJobArtifactsProcedure is the fully-qualified name of the
53+ // JobArtifactService's ListJobArtifacts RPC.
54+ JobArtifactServiceListJobArtifactsProcedure = "/ermite.JobArtifactService/ListJobArtifacts"
55+ // JobArtifactServiceDownloadJobArtifactProcedure is the fully-qualified name of the
56+ // JobArtifactService's DownloadJobArtifact RPC.
57+ JobArtifactServiceDownloadJobArtifactProcedure = "/ermite.JobArtifactService/DownloadJobArtifact"
58+ // JobArtifactServiceDeleteJobArtifactProcedure is the fully-qualified name of the
59+ // JobArtifactService's DeleteJobArtifact RPC.
60+ JobArtifactServiceDeleteJobArtifactProcedure = "/ermite.JobArtifactService/DeleteJobArtifact"
61+ // ArtifactServiceListArtifactsProcedure is the fully-qualified name of the ArtifactService's
62+ // ListArtifacts RPC.
63+ ArtifactServiceListArtifactsProcedure = "/ermite.ArtifactService/ListArtifacts"
64+ // ArtifactServiceDownloadArtifactProcedure is the fully-qualified name of the ArtifactService's
65+ // DownloadArtifact RPC.
66+ ArtifactServiceDownloadArtifactProcedure = "/ermite.ArtifactService/DownloadArtifact"
67+ // ArtifactServiceDeleteArtifactProcedure is the fully-qualified name of the ArtifactService's
68+ // DeleteArtifact RPC.
69+ ArtifactServiceDeleteArtifactProcedure = "/ermite.ArtifactService/DeleteArtifact"
70+)
71+
72+// JobArtifactServiceClient is a client for the ermite.JobArtifactService service.
73+type JobArtifactServiceClient interface {
74+ // CreateJobArtifact begins the upload of an artifact of the job's run and
75+ // returns its id. Fails with invalid_argument if the name or expires_at break
76+ // a rule, already_exists if an artifact of that name was finalized by a job
77+ // of the same attempt of the run (the uploader deletes it first to replace
78+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
79+ // repository already use all their space. A pending artifact of the same
80+ // job and name is discarded: a new create is a new upload.
81+ CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error)
82+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
83+ // client stream: the first message names the job, the artifact and the
84+ // block, every message may carry data, and the block is the data of all the
85+ // messages in order. The block is stored when the client closes the stream
86+ // and the server answers; a stream that breaks or fails stores nothing.
87+ // Storing a block id again replaces the block, so a retry is safe. Blocks
88+ // that the commit does not name are dropped.
89+ //
90+ // Fails with not_found if the artifact is not a pending artifact of this job,
91+ // failed_precondition if it is already committed, invalid_argument if a rule
92+ // of the messages is broken, and resource_exhausted if the blocks of the
93+ // artifact would exceed the size of one artifact or the space of the
94+ // repository.
95+ UploadJobArtifactBlock(context.Context) *connect.ClientStreamForClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse]
96+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
97+ // in that order (Azure's Put Block List). An empty list is an empty content
98+ // (a 0-byte upload). The server then knows the size and the digest, and
99+ // drops the blocks. A repeat of the same call after a success returns the
100+ // same result; a different list on a committed artifact is
101+ // failed_precondition. Fails with not_found if the artifact is not a pending
102+ // artifact of this job, and invalid_argument if a block id was never
103+ // uploaded or the list has more than 50,000 ids.
104+ CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error)
105+ // FinalizeJobArtifact makes the latest committed artifact of the job with
106+ // that name visible to the run, and returns it. An artifact of the same name
107+ // from an earlier attempt of the run is deleted at the same moment (a re-run
108+ // replaces what the first attempt uploaded). A repeat after a success
109+ // returns the same artifact. Fails with not_found if the job has no pending
110+ // artifact of that name, failed_precondition if it is not committed,
111+ // invalid_argument if digest is set and differs from the content, and
112+ // already_exists if a job of the same attempt finalized an artifact of that
113+ // name in the meantime.
114+ FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error)
115+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
116+ // all attempts, by id. An empty list is not an error.
117+ ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error)
118+ // DownloadJobArtifact streams the content of an artifact of the job's run.
119+ // The first message carries the artifact, then the chunks follow in order
120+ // from offset. A client that loses the stream calls again with the offset
121+ // after the last byte it received. Fails with not_found if the artifact is
122+ // not a finalized artifact of the run (or has expired), and out_of_range if
123+ // offset is beyond its size.
124+ DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadJobArtifactResponse], error)
125+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
126+ // run (upload-artifact's "overwrite", and its merge action's
127+ // "delete-merged"). Fails with not_found if there is none.
128+ DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error)
129+}
130+
131+// NewJobArtifactServiceClient constructs a client for the ermite.JobArtifactService service. By
132+// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses,
133+// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the
134+// connect.WithGRPC() or connect.WithGRPCWeb() options.
135+//
136+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
137+// http://api.acme.com or https://acme.com/grpc).
138+func NewJobArtifactServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) JobArtifactServiceClient {
139+ baseURL = strings.TrimRight(baseURL, "/")
140+ jobArtifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("JobArtifactService").Methods()
141+ return &jobArtifactServiceClient{
142+ createJobArtifact: connect.NewClient[ermite.CreateJobArtifactRequest, ermite.CreateJobArtifactResponse](
143+ httpClient,
144+ baseURL+JobArtifactServiceCreateJobArtifactProcedure,
145+ connect.WithSchema(jobArtifactServiceMethods.ByName("CreateJobArtifact")),
146+ connect.WithClientOptions(opts...),
147+ ),
148+ uploadJobArtifactBlock: connect.NewClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse](
149+ httpClient,
150+ baseURL+JobArtifactServiceUploadJobArtifactBlockProcedure,
151+ connect.WithSchema(jobArtifactServiceMethods.ByName("UploadJobArtifactBlock")),
152+ connect.WithClientOptions(opts...),
153+ ),
154+ commitJobArtifact: connect.NewClient[ermite.CommitJobArtifactRequest, ermite.CommitJobArtifactResponse](
155+ httpClient,
156+ baseURL+JobArtifactServiceCommitJobArtifactProcedure,
157+ connect.WithSchema(jobArtifactServiceMethods.ByName("CommitJobArtifact")),
158+ connect.WithClientOptions(opts...),
159+ ),
160+ finalizeJobArtifact: connect.NewClient[ermite.FinalizeJobArtifactRequest, ermite.FinalizeJobArtifactResponse](
161+ httpClient,
162+ baseURL+JobArtifactServiceFinalizeJobArtifactProcedure,
163+ connect.WithSchema(jobArtifactServiceMethods.ByName("FinalizeJobArtifact")),
164+ connect.WithClientOptions(opts...),
165+ ),
166+ listJobArtifacts: connect.NewClient[ermite.ListJobArtifactsRequest, ermite.ListJobArtifactsResponse](
167+ httpClient,
168+ baseURL+JobArtifactServiceListJobArtifactsProcedure,
169+ connect.WithSchema(jobArtifactServiceMethods.ByName("ListJobArtifacts")),
170+ connect.WithClientOptions(opts...),
171+ ),
172+ downloadJobArtifact: connect.NewClient[ermite.DownloadJobArtifactRequest, ermite.DownloadJobArtifactResponse](
173+ httpClient,
174+ baseURL+JobArtifactServiceDownloadJobArtifactProcedure,
175+ connect.WithSchema(jobArtifactServiceMethods.ByName("DownloadJobArtifact")),
176+ connect.WithClientOptions(opts...),
177+ ),
178+ deleteJobArtifact: connect.NewClient[ermite.DeleteJobArtifactRequest, ermite.DeleteJobArtifactResponse](
179+ httpClient,
180+ baseURL+JobArtifactServiceDeleteJobArtifactProcedure,
181+ connect.WithSchema(jobArtifactServiceMethods.ByName("DeleteJobArtifact")),
182+ connect.WithClientOptions(opts...),
183+ ),
184+ }
185+}
186+
187+// jobArtifactServiceClient implements JobArtifactServiceClient.
188+type jobArtifactServiceClient struct {
189+ createJobArtifact *connect.Client[ermite.CreateJobArtifactRequest, ermite.CreateJobArtifactResponse]
190+ uploadJobArtifactBlock *connect.Client[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse]
191+ commitJobArtifact *connect.Client[ermite.CommitJobArtifactRequest, ermite.CommitJobArtifactResponse]
192+ finalizeJobArtifact *connect.Client[ermite.FinalizeJobArtifactRequest, ermite.FinalizeJobArtifactResponse]
193+ listJobArtifacts *connect.Client[ermite.ListJobArtifactsRequest, ermite.ListJobArtifactsResponse]
194+ downloadJobArtifact *connect.Client[ermite.DownloadJobArtifactRequest, ermite.DownloadJobArtifactResponse]
195+ deleteJobArtifact *connect.Client[ermite.DeleteJobArtifactRequest, ermite.DeleteJobArtifactResponse]
196+}
197+
198+// CreateJobArtifact calls ermite.JobArtifactService.CreateJobArtifact.
199+func (c *jobArtifactServiceClient) CreateJobArtifact(ctx context.Context, req *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error) {
200+ return c.createJobArtifact.CallUnary(ctx, req)
201+}
202+
203+// UploadJobArtifactBlock calls ermite.JobArtifactService.UploadJobArtifactBlock.
204+func (c *jobArtifactServiceClient) UploadJobArtifactBlock(ctx context.Context) *connect.ClientStreamForClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse] {
205+ return c.uploadJobArtifactBlock.CallClientStream(ctx)
206+}
207+
208+// CommitJobArtifact calls ermite.JobArtifactService.CommitJobArtifact.
209+func (c *jobArtifactServiceClient) CommitJobArtifact(ctx context.Context, req *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error) {
210+ return c.commitJobArtifact.CallUnary(ctx, req)
211+}
212+
213+// FinalizeJobArtifact calls ermite.JobArtifactService.FinalizeJobArtifact.
214+func (c *jobArtifactServiceClient) FinalizeJobArtifact(ctx context.Context, req *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error) {
215+ return c.finalizeJobArtifact.CallUnary(ctx, req)
216+}
217+
218+// ListJobArtifacts calls ermite.JobArtifactService.ListJobArtifacts.
219+func (c *jobArtifactServiceClient) ListJobArtifacts(ctx context.Context, req *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error) {
220+ return c.listJobArtifacts.CallUnary(ctx, req)
221+}
222+
223+// DownloadJobArtifact calls ermite.JobArtifactService.DownloadJobArtifact.
224+func (c *jobArtifactServiceClient) DownloadJobArtifact(ctx context.Context, req *connect.Request[ermite.DownloadJobArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadJobArtifactResponse], error) {
225+ return c.downloadJobArtifact.CallServerStream(ctx, req)
226+}
227+
228+// DeleteJobArtifact calls ermite.JobArtifactService.DeleteJobArtifact.
229+func (c *jobArtifactServiceClient) DeleteJobArtifact(ctx context.Context, req *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error) {
230+ return c.deleteJobArtifact.CallUnary(ctx, req)
231+}
232+
233+// JobArtifactServiceHandler is an implementation of the ermite.JobArtifactService service.
234+type JobArtifactServiceHandler interface {
235+ // CreateJobArtifact begins the upload of an artifact of the job's run and
236+ // returns its id. Fails with invalid_argument if the name or expires_at break
237+ // a rule, already_exists if an artifact of that name was finalized by a job
238+ // of the same attempt of the run (the uploader deletes it first to replace
239+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
240+ // repository already use all their space. A pending artifact of the same
241+ // job and name is discarded: a new create is a new upload.
242+ CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error)
243+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
244+ // client stream: the first message names the job, the artifact and the
245+ // block, every message may carry data, and the block is the data of all the
246+ // messages in order. The block is stored when the client closes the stream
247+ // and the server answers; a stream that breaks or fails stores nothing.
248+ // Storing a block id again replaces the block, so a retry is safe. Blocks
249+ // that the commit does not name are dropped.
250+ //
251+ // Fails with not_found if the artifact is not a pending artifact of this job,
252+ // failed_precondition if it is already committed, invalid_argument if a rule
253+ // of the messages is broken, and resource_exhausted if the blocks of the
254+ // artifact would exceed the size of one artifact or the space of the
255+ // repository.
256+ UploadJobArtifactBlock(context.Context, *connect.ClientStream[ermite.UploadJobArtifactBlockRequest]) (*connect.Response[ermite.UploadJobArtifactBlockResponse], error)
257+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
258+ // in that order (Azure's Put Block List). An empty list is an empty content
259+ // (a 0-byte upload). The server then knows the size and the digest, and
260+ // drops the blocks. A repeat of the same call after a success returns the
261+ // same result; a different list on a committed artifact is
262+ // failed_precondition. Fails with not_found if the artifact is not a pending
263+ // artifact of this job, and invalid_argument if a block id was never
264+ // uploaded or the list has more than 50,000 ids.
265+ CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error)
266+ // FinalizeJobArtifact makes the latest committed artifact of the job with
267+ // that name visible to the run, and returns it. An artifact of the same name
268+ // from an earlier attempt of the run is deleted at the same moment (a re-run
269+ // replaces what the first attempt uploaded). A repeat after a success
270+ // returns the same artifact. Fails with not_found if the job has no pending
271+ // artifact of that name, failed_precondition if it is not committed,
272+ // invalid_argument if digest is set and differs from the content, and
273+ // already_exists if a job of the same attempt finalized an artifact of that
274+ // name in the meantime.
275+ FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error)
276+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
277+ // all attempts, by id. An empty list is not an error.
278+ ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error)
279+ // DownloadJobArtifact streams the content of an artifact of the job's run.
280+ // The first message carries the artifact, then the chunks follow in order
281+ // from offset. A client that loses the stream calls again with the offset
282+ // after the last byte it received. Fails with not_found if the artifact is
283+ // not a finalized artifact of the run (or has expired), and out_of_range if
284+ // offset is beyond its size.
285+ DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest], *connect.ServerStream[ermite.DownloadJobArtifactResponse]) error
286+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
287+ // run (upload-artifact's "overwrite", and its merge action's
288+ // "delete-merged"). Fails with not_found if there is none.
289+ DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error)
290+}
291+
292+// NewJobArtifactServiceHandler builds an HTTP handler from the service implementation. It returns
293+// the path on which to mount the handler and the handler itself.
294+//
295+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
296+// and JSON codecs. They also support gzip compression.
297+func NewJobArtifactServiceHandler(svc JobArtifactServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
298+ jobArtifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("JobArtifactService").Methods()
299+ jobArtifactServiceCreateJobArtifactHandler := connect.NewUnaryHandler(
300+ JobArtifactServiceCreateJobArtifactProcedure,
301+ svc.CreateJobArtifact,
302+ connect.WithSchema(jobArtifactServiceMethods.ByName("CreateJobArtifact")),
303+ connect.WithHandlerOptions(opts...),
304+ )
305+ jobArtifactServiceUploadJobArtifactBlockHandler := connect.NewClientStreamHandler(
306+ JobArtifactServiceUploadJobArtifactBlockProcedure,
307+ svc.UploadJobArtifactBlock,
308+ connect.WithSchema(jobArtifactServiceMethods.ByName("UploadJobArtifactBlock")),
309+ connect.WithHandlerOptions(opts...),
310+ )
311+ jobArtifactServiceCommitJobArtifactHandler := connect.NewUnaryHandler(
312+ JobArtifactServiceCommitJobArtifactProcedure,
313+ svc.CommitJobArtifact,
314+ connect.WithSchema(jobArtifactServiceMethods.ByName("CommitJobArtifact")),
315+ connect.WithHandlerOptions(opts...),
316+ )
317+ jobArtifactServiceFinalizeJobArtifactHandler := connect.NewUnaryHandler(
318+ JobArtifactServiceFinalizeJobArtifactProcedure,
319+ svc.FinalizeJobArtifact,
320+ connect.WithSchema(jobArtifactServiceMethods.ByName("FinalizeJobArtifact")),
321+ connect.WithHandlerOptions(opts...),
322+ )
323+ jobArtifactServiceListJobArtifactsHandler := connect.NewUnaryHandler(
324+ JobArtifactServiceListJobArtifactsProcedure,
325+ svc.ListJobArtifacts,
326+ connect.WithSchema(jobArtifactServiceMethods.ByName("ListJobArtifacts")),
327+ connect.WithHandlerOptions(opts...),
328+ )
329+ jobArtifactServiceDownloadJobArtifactHandler := connect.NewServerStreamHandler(
330+ JobArtifactServiceDownloadJobArtifactProcedure,
331+ svc.DownloadJobArtifact,
332+ connect.WithSchema(jobArtifactServiceMethods.ByName("DownloadJobArtifact")),
333+ connect.WithHandlerOptions(opts...),
334+ )
335+ jobArtifactServiceDeleteJobArtifactHandler := connect.NewUnaryHandler(
336+ JobArtifactServiceDeleteJobArtifactProcedure,
337+ svc.DeleteJobArtifact,
338+ connect.WithSchema(jobArtifactServiceMethods.ByName("DeleteJobArtifact")),
339+ connect.WithHandlerOptions(opts...),
340+ )
341+ return "/ermite.JobArtifactService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
342+ switch r.URL.Path {
343+ case JobArtifactServiceCreateJobArtifactProcedure:
344+ jobArtifactServiceCreateJobArtifactHandler.ServeHTTP(w, r)
345+ case JobArtifactServiceUploadJobArtifactBlockProcedure:
346+ jobArtifactServiceUploadJobArtifactBlockHandler.ServeHTTP(w, r)
347+ case JobArtifactServiceCommitJobArtifactProcedure:
348+ jobArtifactServiceCommitJobArtifactHandler.ServeHTTP(w, r)
349+ case JobArtifactServiceFinalizeJobArtifactProcedure:
350+ jobArtifactServiceFinalizeJobArtifactHandler.ServeHTTP(w, r)
351+ case JobArtifactServiceListJobArtifactsProcedure:
352+ jobArtifactServiceListJobArtifactsHandler.ServeHTTP(w, r)
353+ case JobArtifactServiceDownloadJobArtifactProcedure:
354+ jobArtifactServiceDownloadJobArtifactHandler.ServeHTTP(w, r)
355+ case JobArtifactServiceDeleteJobArtifactProcedure:
356+ jobArtifactServiceDeleteJobArtifactHandler.ServeHTTP(w, r)
357+ default:
358+ http.NotFound(w, r)
359+ }
360+ })
361+}
362+
363+// UnimplementedJobArtifactServiceHandler returns CodeUnimplemented from all methods.
364+type UnimplementedJobArtifactServiceHandler struct{}
365+
366+func (UnimplementedJobArtifactServiceHandler) CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error) {
367+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.CreateJobArtifact is not implemented"))
368+}
369+
370+func (UnimplementedJobArtifactServiceHandler) UploadJobArtifactBlock(context.Context, *connect.ClientStream[ermite.UploadJobArtifactBlockRequest]) (*connect.Response[ermite.UploadJobArtifactBlockResponse], error) {
371+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.UploadJobArtifactBlock is not implemented"))
372+}
373+
374+func (UnimplementedJobArtifactServiceHandler) CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error) {
375+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.CommitJobArtifact is not implemented"))
376+}
377+
378+func (UnimplementedJobArtifactServiceHandler) FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error) {
379+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.FinalizeJobArtifact is not implemented"))
380+}
381+
382+func (UnimplementedJobArtifactServiceHandler) ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error) {
383+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.ListJobArtifacts is not implemented"))
384+}
385+
386+func (UnimplementedJobArtifactServiceHandler) DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest], *connect.ServerStream[ermite.DownloadJobArtifactResponse]) error {
387+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.DownloadJobArtifact is not implemented"))
388+}
389+
390+func (UnimplementedJobArtifactServiceHandler) DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error) {
391+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.DeleteJobArtifact is not implemented"))
392+}
393+
394+// ArtifactServiceClient is a client for the ermite.ArtifactService service.
395+type ArtifactServiceClient interface {
396+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
397+ // artifacts of the repository use.
398+ ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error)
399+ // DownloadArtifact streams the content of an artifact, as
400+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
401+ // artifact is not an artifact of the repository, and out_of_range if offset
402+ // is beyond its size.
403+ DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadArtifactResponse], error)
404+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
405+ // artifact of the repository.
406+ DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error)
407+}
408+
409+// NewArtifactServiceClient constructs a client for the ermite.ArtifactService service. By default,
410+// it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and
411+// sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC()
412+// or connect.WithGRPCWeb() options.
413+//
414+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
415+// http://api.acme.com or https://acme.com/grpc).
416+func NewArtifactServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ArtifactServiceClient {
417+ baseURL = strings.TrimRight(baseURL, "/")
418+ artifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("ArtifactService").Methods()
419+ return &artifactServiceClient{
420+ listArtifacts: connect.NewClient[ermite.ListArtifactsRequest, ermite.ListArtifactsResponse](
421+ httpClient,
422+ baseURL+ArtifactServiceListArtifactsProcedure,
423+ connect.WithSchema(artifactServiceMethods.ByName("ListArtifacts")),
424+ connect.WithClientOptions(opts...),
425+ ),
426+ downloadArtifact: connect.NewClient[ermite.DownloadArtifactRequest, ermite.DownloadArtifactResponse](
427+ httpClient,
428+ baseURL+ArtifactServiceDownloadArtifactProcedure,
429+ connect.WithSchema(artifactServiceMethods.ByName("DownloadArtifact")),
430+ connect.WithClientOptions(opts...),
431+ ),
432+ deleteArtifact: connect.NewClient[ermite.DeleteArtifactRequest, ermite.DeleteArtifactResponse](
433+ httpClient,
434+ baseURL+ArtifactServiceDeleteArtifactProcedure,
435+ connect.WithSchema(artifactServiceMethods.ByName("DeleteArtifact")),
436+ connect.WithClientOptions(opts...),
437+ ),
438+ }
439+}
440+
441+// artifactServiceClient implements ArtifactServiceClient.
442+type artifactServiceClient struct {
443+ listArtifacts *connect.Client[ermite.ListArtifactsRequest, ermite.ListArtifactsResponse]
444+ downloadArtifact *connect.Client[ermite.DownloadArtifactRequest, ermite.DownloadArtifactResponse]
445+ deleteArtifact *connect.Client[ermite.DeleteArtifactRequest, ermite.DeleteArtifactResponse]
446+}
447+
448+// ListArtifacts calls ermite.ArtifactService.ListArtifacts.
449+func (c *artifactServiceClient) ListArtifacts(ctx context.Context, req *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error) {
450+ return c.listArtifacts.CallUnary(ctx, req)
451+}
452+
453+// DownloadArtifact calls ermite.ArtifactService.DownloadArtifact.
454+func (c *artifactServiceClient) DownloadArtifact(ctx context.Context, req *connect.Request[ermite.DownloadArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadArtifactResponse], error) {
455+ return c.downloadArtifact.CallServerStream(ctx, req)
456+}
457+
458+// DeleteArtifact calls ermite.ArtifactService.DeleteArtifact.
459+func (c *artifactServiceClient) DeleteArtifact(ctx context.Context, req *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error) {
460+ return c.deleteArtifact.CallUnary(ctx, req)
461+}
462+
463+// ArtifactServiceHandler is an implementation of the ermite.ArtifactService service.
464+type ArtifactServiceHandler interface {
465+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
466+ // artifacts of the repository use.
467+ ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error)
468+ // DownloadArtifact streams the content of an artifact, as
469+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
470+ // artifact is not an artifact of the repository, and out_of_range if offset
471+ // is beyond its size.
472+ DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest], *connect.ServerStream[ermite.DownloadArtifactResponse]) error
473+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
474+ // artifact of the repository.
475+ DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error)
476+}
477+
478+// NewArtifactServiceHandler builds an HTTP handler from the service implementation. It returns the
479+// path on which to mount the handler and the handler itself.
480+//
481+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
482+// and JSON codecs. They also support gzip compression.
483+func NewArtifactServiceHandler(svc ArtifactServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
484+ artifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("ArtifactService").Methods()
485+ artifactServiceListArtifactsHandler := connect.NewUnaryHandler(
486+ ArtifactServiceListArtifactsProcedure,
487+ svc.ListArtifacts,
488+ connect.WithSchema(artifactServiceMethods.ByName("ListArtifacts")),
489+ connect.WithHandlerOptions(opts...),
490+ )
491+ artifactServiceDownloadArtifactHandler := connect.NewServerStreamHandler(
492+ ArtifactServiceDownloadArtifactProcedure,
493+ svc.DownloadArtifact,
494+ connect.WithSchema(artifactServiceMethods.ByName("DownloadArtifact")),
495+ connect.WithHandlerOptions(opts...),
496+ )
497+ artifactServiceDeleteArtifactHandler := connect.NewUnaryHandler(
498+ ArtifactServiceDeleteArtifactProcedure,
499+ svc.DeleteArtifact,
500+ connect.WithSchema(artifactServiceMethods.ByName("DeleteArtifact")),
501+ connect.WithHandlerOptions(opts...),
502+ )
503+ return "/ermite.ArtifactService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
504+ switch r.URL.Path {
505+ case ArtifactServiceListArtifactsProcedure:
506+ artifactServiceListArtifactsHandler.ServeHTTP(w, r)
507+ case ArtifactServiceDownloadArtifactProcedure:
508+ artifactServiceDownloadArtifactHandler.ServeHTTP(w, r)
509+ case ArtifactServiceDeleteArtifactProcedure:
510+ artifactServiceDeleteArtifactHandler.ServeHTTP(w, r)
511+ default:
512+ http.NotFound(w, r)
513+ }
514+ })
515+}
516+
517+// UnimplementedArtifactServiceHandler returns CodeUnimplemented from all methods.
518+type UnimplementedArtifactServiceHandler struct{}
519+
520+func (UnimplementedArtifactServiceHandler) ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error) {
521+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.ListArtifacts is not implemented"))
522+}
523+
524+func (UnimplementedArtifactServiceHandler) DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest], *connect.ServerStream[ermite.DownloadArtifactResponse]) error {
525+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.DownloadArtifact is not implemented"))
526+}
527+
528+func (UnimplementedArtifactServiceHandler) DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error) {
529+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.DeleteArtifact is not implemented"))
530+}
@@ -0,0 +1,530 @@
1+// SPDX-License-Identifier: MIT
2+
3+// Code generated by protoc-gen-connect-go. DO NOT EDIT.
4+//
5+// Source: ermite/artifact.proto
6+
7+package ermiteconnect
8+
9+import (
10+ ermite "bnema.dev/ermite-api/gen/ermite"
11+ connect "connectrpc.com/connect"
12+ context "context"
13+ errors "errors"
14+ http "net/http"
15+ strings "strings"
16+)
17+
18+// This is a compile-time assertion to ensure that this generated file and the connect package are
19+// compatible. If you get a compiler error that this constant is not defined, this code was
20+// generated with a version of connect newer than the one compiled into your binary. You can fix the
21+// problem by either regenerating this code with an older version of connect or updating the connect
22+// version compiled into your binary.
23+const _ = connect.IsAtLeastVersion1_13_0
24+
25+const (
26+ // JobArtifactServiceName is the fully-qualified name of the JobArtifactService service.
27+ JobArtifactServiceName = "ermite.JobArtifactService"
28+ // ArtifactServiceName is the fully-qualified name of the ArtifactService service.
29+ ArtifactServiceName = "ermite.ArtifactService"
30+)
31+
32+// These constants are the fully-qualified names of the RPCs defined in this package. They're
33+// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
34+//
35+// Note that these are different from the fully-qualified method names used by
36+// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
37+// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
38+// period.
39+const (
40+ // JobArtifactServiceCreateJobArtifactProcedure is the fully-qualified name of the
41+ // JobArtifactService's CreateJobArtifact RPC.
42+ JobArtifactServiceCreateJobArtifactProcedure = "/ermite.JobArtifactService/CreateJobArtifact"
43+ // JobArtifactServiceUploadJobArtifactBlockProcedure is the fully-qualified name of the
44+ // JobArtifactService's UploadJobArtifactBlock RPC.
45+ JobArtifactServiceUploadJobArtifactBlockProcedure = "/ermite.JobArtifactService/UploadJobArtifactBlock"
46+ // JobArtifactServiceCommitJobArtifactProcedure is the fully-qualified name of the
47+ // JobArtifactService's CommitJobArtifact RPC.
48+ JobArtifactServiceCommitJobArtifactProcedure = "/ermite.JobArtifactService/CommitJobArtifact"
49+ // JobArtifactServiceFinalizeJobArtifactProcedure is the fully-qualified name of the
50+ // JobArtifactService's FinalizeJobArtifact RPC.
51+ JobArtifactServiceFinalizeJobArtifactProcedure = "/ermite.JobArtifactService/FinalizeJobArtifact"
52+ // JobArtifactServiceListJobArtifactsProcedure is the fully-qualified name of the
53+ // JobArtifactService's ListJobArtifacts RPC.
54+ JobArtifactServiceListJobArtifactsProcedure = "/ermite.JobArtifactService/ListJobArtifacts"
55+ // JobArtifactServiceDownloadJobArtifactProcedure is the fully-qualified name of the
56+ // JobArtifactService's DownloadJobArtifact RPC.
57+ JobArtifactServiceDownloadJobArtifactProcedure = "/ermite.JobArtifactService/DownloadJobArtifact"
58+ // JobArtifactServiceDeleteJobArtifactProcedure is the fully-qualified name of the
59+ // JobArtifactService's DeleteJobArtifact RPC.
60+ JobArtifactServiceDeleteJobArtifactProcedure = "/ermite.JobArtifactService/DeleteJobArtifact"
61+ // ArtifactServiceListArtifactsProcedure is the fully-qualified name of the ArtifactService's
62+ // ListArtifacts RPC.
63+ ArtifactServiceListArtifactsProcedure = "/ermite.ArtifactService/ListArtifacts"
64+ // ArtifactServiceDownloadArtifactProcedure is the fully-qualified name of the ArtifactService's
65+ // DownloadArtifact RPC.
66+ ArtifactServiceDownloadArtifactProcedure = "/ermite.ArtifactService/DownloadArtifact"
67+ // ArtifactServiceDeleteArtifactProcedure is the fully-qualified name of the ArtifactService's
68+ // DeleteArtifact RPC.
69+ ArtifactServiceDeleteArtifactProcedure = "/ermite.ArtifactService/DeleteArtifact"
70+)
71+
72+// JobArtifactServiceClient is a client for the ermite.JobArtifactService service.
73+type JobArtifactServiceClient interface {
74+ // CreateJobArtifact begins the upload of an artifact of the job's run and
75+ // returns its id. Fails with invalid_argument if the name or expires_at break
76+ // a rule, already_exists if an artifact of that name was finalized by a job
77+ // of the same attempt of the run (the uploader deletes it first to replace
78+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
79+ // repository already use all their space. A pending artifact of the same
80+ // job and name is discarded: a new create is a new upload.
81+ CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error)
82+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
83+ // client stream: the first message names the job, the artifact and the
84+ // block, every message may carry data, and the block is the data of all the
85+ // messages in order. The block is stored when the client closes the stream
86+ // and the server answers; a stream that breaks or fails stores nothing.
87+ // Storing a block id again replaces the block, so a retry is safe. Blocks
88+ // that the commit does not name are dropped.
89+ //
90+ // Fails with not_found if the artifact is not a pending artifact of this job,
91+ // failed_precondition if it is already committed, invalid_argument if a rule
92+ // of the messages is broken, and resource_exhausted if the blocks of the
93+ // artifact would exceed the size of one artifact or the space of the
94+ // repository.
95+ UploadJobArtifactBlock(context.Context) *connect.ClientStreamForClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse]
96+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
97+ // in that order (Azure's Put Block List). An empty list is an empty content
98+ // (a 0-byte upload). The server then knows the size and the digest, and
99+ // drops the blocks. A repeat of the same call after a success returns the
100+ // same result; a different list on a committed artifact is
101+ // failed_precondition. Fails with not_found if the artifact is not a pending
102+ // artifact of this job, and invalid_argument if a block id was never
103+ // uploaded or the list has more than 50,000 ids.
104+ CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error)
105+ // FinalizeJobArtifact makes the latest committed artifact of the job with
106+ // that name visible to the run, and returns it. An artifact of the same name
107+ // from an earlier attempt of the run is deleted at the same moment (a re-run
108+ // replaces what the first attempt uploaded). A repeat after a success
109+ // returns the same artifact. Fails with not_found if the job has no pending
110+ // artifact of that name, failed_precondition if it is not committed,
111+ // invalid_argument if digest is set and differs from the content, and
112+ // already_exists if a job of the same attempt finalized an artifact of that
113+ // name in the meantime.
114+ FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error)
115+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
116+ // all attempts, by id. An empty list is not an error.
117+ ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error)
118+ // DownloadJobArtifact streams the content of an artifact of the job's run.
119+ // The first message carries the artifact, then the chunks follow in order
120+ // from offset. A client that loses the stream calls again with the offset
121+ // after the last byte it received. Fails with not_found if the artifact is
122+ // not a finalized artifact of the run (or has expired), and out_of_range if
123+ // offset is beyond its size.
124+ DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadJobArtifactResponse], error)
125+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
126+ // run (upload-artifact's "overwrite", and its merge action's
127+ // "delete-merged"). Fails with not_found if there is none.
128+ DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error)
129+}
130+
131+// NewJobArtifactServiceClient constructs a client for the ermite.JobArtifactService service. By
132+// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses,
133+// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the
134+// connect.WithGRPC() or connect.WithGRPCWeb() options.
135+//
136+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
137+// http://api.acme.com or https://acme.com/grpc).
138+func NewJobArtifactServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) JobArtifactServiceClient {
139+ baseURL = strings.TrimRight(baseURL, "/")
140+ jobArtifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("JobArtifactService").Methods()
141+ return &jobArtifactServiceClient{
142+ createJobArtifact: connect.NewClient[ermite.CreateJobArtifactRequest, ermite.CreateJobArtifactResponse](
143+ httpClient,
144+ baseURL+JobArtifactServiceCreateJobArtifactProcedure,
145+ connect.WithSchema(jobArtifactServiceMethods.ByName("CreateJobArtifact")),
146+ connect.WithClientOptions(opts...),
147+ ),
148+ uploadJobArtifactBlock: connect.NewClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse](
149+ httpClient,
150+ baseURL+JobArtifactServiceUploadJobArtifactBlockProcedure,
151+ connect.WithSchema(jobArtifactServiceMethods.ByName("UploadJobArtifactBlock")),
152+ connect.WithClientOptions(opts...),
153+ ),
154+ commitJobArtifact: connect.NewClient[ermite.CommitJobArtifactRequest, ermite.CommitJobArtifactResponse](
155+ httpClient,
156+ baseURL+JobArtifactServiceCommitJobArtifactProcedure,
157+ connect.WithSchema(jobArtifactServiceMethods.ByName("CommitJobArtifact")),
158+ connect.WithClientOptions(opts...),
159+ ),
160+ finalizeJobArtifact: connect.NewClient[ermite.FinalizeJobArtifactRequest, ermite.FinalizeJobArtifactResponse](
161+ httpClient,
162+ baseURL+JobArtifactServiceFinalizeJobArtifactProcedure,
163+ connect.WithSchema(jobArtifactServiceMethods.ByName("FinalizeJobArtifact")),
164+ connect.WithClientOptions(opts...),
165+ ),
166+ listJobArtifacts: connect.NewClient[ermite.ListJobArtifactsRequest, ermite.ListJobArtifactsResponse](
167+ httpClient,
168+ baseURL+JobArtifactServiceListJobArtifactsProcedure,
169+ connect.WithSchema(jobArtifactServiceMethods.ByName("ListJobArtifacts")),
170+ connect.WithClientOptions(opts...),
171+ ),
172+ downloadJobArtifact: connect.NewClient[ermite.DownloadJobArtifactRequest, ermite.DownloadJobArtifactResponse](
173+ httpClient,
174+ baseURL+JobArtifactServiceDownloadJobArtifactProcedure,
175+ connect.WithSchema(jobArtifactServiceMethods.ByName("DownloadJobArtifact")),
176+ connect.WithClientOptions(opts...),
177+ ),
178+ deleteJobArtifact: connect.NewClient[ermite.DeleteJobArtifactRequest, ermite.DeleteJobArtifactResponse](
179+ httpClient,
180+ baseURL+JobArtifactServiceDeleteJobArtifactProcedure,
181+ connect.WithSchema(jobArtifactServiceMethods.ByName("DeleteJobArtifact")),
182+ connect.WithClientOptions(opts...),
183+ ),
184+ }
185+}
186+
187+// jobArtifactServiceClient implements JobArtifactServiceClient.
188+type jobArtifactServiceClient struct {
189+ createJobArtifact *connect.Client[ermite.CreateJobArtifactRequest, ermite.CreateJobArtifactResponse]
190+ uploadJobArtifactBlock *connect.Client[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse]
191+ commitJobArtifact *connect.Client[ermite.CommitJobArtifactRequest, ermite.CommitJobArtifactResponse]
192+ finalizeJobArtifact *connect.Client[ermite.FinalizeJobArtifactRequest, ermite.FinalizeJobArtifactResponse]
193+ listJobArtifacts *connect.Client[ermite.ListJobArtifactsRequest, ermite.ListJobArtifactsResponse]
194+ downloadJobArtifact *connect.Client[ermite.DownloadJobArtifactRequest, ermite.DownloadJobArtifactResponse]
195+ deleteJobArtifact *connect.Client[ermite.DeleteJobArtifactRequest, ermite.DeleteJobArtifactResponse]
196+}
197+
198+// CreateJobArtifact calls ermite.JobArtifactService.CreateJobArtifact.
199+func (c *jobArtifactServiceClient) CreateJobArtifact(ctx context.Context, req *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error) {
200+ return c.createJobArtifact.CallUnary(ctx, req)
201+}
202+
203+// UploadJobArtifactBlock calls ermite.JobArtifactService.UploadJobArtifactBlock.
204+func (c *jobArtifactServiceClient) UploadJobArtifactBlock(ctx context.Context) *connect.ClientStreamForClient[ermite.UploadJobArtifactBlockRequest, ermite.UploadJobArtifactBlockResponse] {
205+ return c.uploadJobArtifactBlock.CallClientStream(ctx)
206+}
207+
208+// CommitJobArtifact calls ermite.JobArtifactService.CommitJobArtifact.
209+func (c *jobArtifactServiceClient) CommitJobArtifact(ctx context.Context, req *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error) {
210+ return c.commitJobArtifact.CallUnary(ctx, req)
211+}
212+
213+// FinalizeJobArtifact calls ermite.JobArtifactService.FinalizeJobArtifact.
214+func (c *jobArtifactServiceClient) FinalizeJobArtifact(ctx context.Context, req *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error) {
215+ return c.finalizeJobArtifact.CallUnary(ctx, req)
216+}
217+
218+// ListJobArtifacts calls ermite.JobArtifactService.ListJobArtifacts.
219+func (c *jobArtifactServiceClient) ListJobArtifacts(ctx context.Context, req *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error) {
220+ return c.listJobArtifacts.CallUnary(ctx, req)
221+}
222+
223+// DownloadJobArtifact calls ermite.JobArtifactService.DownloadJobArtifact.
224+func (c *jobArtifactServiceClient) DownloadJobArtifact(ctx context.Context, req *connect.Request[ermite.DownloadJobArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadJobArtifactResponse], error) {
225+ return c.downloadJobArtifact.CallServerStream(ctx, req)
226+}
227+
228+// DeleteJobArtifact calls ermite.JobArtifactService.DeleteJobArtifact.
229+func (c *jobArtifactServiceClient) DeleteJobArtifact(ctx context.Context, req *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error) {
230+ return c.deleteJobArtifact.CallUnary(ctx, req)
231+}
232+
233+// JobArtifactServiceHandler is an implementation of the ermite.JobArtifactService service.
234+type JobArtifactServiceHandler interface {
235+ // CreateJobArtifact begins the upload of an artifact of the job's run and
236+ // returns its id. Fails with invalid_argument if the name or expires_at break
237+ // a rule, already_exists if an artifact of that name was finalized by a job
238+ // of the same attempt of the run (the uploader deletes it first to replace
239+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
240+ // repository already use all their space. A pending artifact of the same
241+ // job and name is discarded: a new create is a new upload.
242+ CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error)
243+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
244+ // client stream: the first message names the job, the artifact and the
245+ // block, every message may carry data, and the block is the data of all the
246+ // messages in order. The block is stored when the client closes the stream
247+ // and the server answers; a stream that breaks or fails stores nothing.
248+ // Storing a block id again replaces the block, so a retry is safe. Blocks
249+ // that the commit does not name are dropped.
250+ //
251+ // Fails with not_found if the artifact is not a pending artifact of this job,
252+ // failed_precondition if it is already committed, invalid_argument if a rule
253+ // of the messages is broken, and resource_exhausted if the blocks of the
254+ // artifact would exceed the size of one artifact or the space of the
255+ // repository.
256+ UploadJobArtifactBlock(context.Context, *connect.ClientStream[ermite.UploadJobArtifactBlockRequest]) (*connect.Response[ermite.UploadJobArtifactBlockResponse], error)
257+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
258+ // in that order (Azure's Put Block List). An empty list is an empty content
259+ // (a 0-byte upload). The server then knows the size and the digest, and
260+ // drops the blocks. A repeat of the same call after a success returns the
261+ // same result; a different list on a committed artifact is
262+ // failed_precondition. Fails with not_found if the artifact is not a pending
263+ // artifact of this job, and invalid_argument if a block id was never
264+ // uploaded or the list has more than 50,000 ids.
265+ CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error)
266+ // FinalizeJobArtifact makes the latest committed artifact of the job with
267+ // that name visible to the run, and returns it. An artifact of the same name
268+ // from an earlier attempt of the run is deleted at the same moment (a re-run
269+ // replaces what the first attempt uploaded). A repeat after a success
270+ // returns the same artifact. Fails with not_found if the job has no pending
271+ // artifact of that name, failed_precondition if it is not committed,
272+ // invalid_argument if digest is set and differs from the content, and
273+ // already_exists if a job of the same attempt finalized an artifact of that
274+ // name in the meantime.
275+ FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error)
276+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
277+ // all attempts, by id. An empty list is not an error.
278+ ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error)
279+ // DownloadJobArtifact streams the content of an artifact of the job's run.
280+ // The first message carries the artifact, then the chunks follow in order
281+ // from offset. A client that loses the stream calls again with the offset
282+ // after the last byte it received. Fails with not_found if the artifact is
283+ // not a finalized artifact of the run (or has expired), and out_of_range if
284+ // offset is beyond its size.
285+ DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest], *connect.ServerStream[ermite.DownloadJobArtifactResponse]) error
286+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
287+ // run (upload-artifact's "overwrite", and its merge action's
288+ // "delete-merged"). Fails with not_found if there is none.
289+ DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error)
290+}
291+
292+// NewJobArtifactServiceHandler builds an HTTP handler from the service implementation. It returns
293+// the path on which to mount the handler and the handler itself.
294+//
295+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
296+// and JSON codecs. They also support gzip compression.
297+func NewJobArtifactServiceHandler(svc JobArtifactServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
298+ jobArtifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("JobArtifactService").Methods()
299+ jobArtifactServiceCreateJobArtifactHandler := connect.NewUnaryHandler(
300+ JobArtifactServiceCreateJobArtifactProcedure,
301+ svc.CreateJobArtifact,
302+ connect.WithSchema(jobArtifactServiceMethods.ByName("CreateJobArtifact")),
303+ connect.WithHandlerOptions(opts...),
304+ )
305+ jobArtifactServiceUploadJobArtifactBlockHandler := connect.NewClientStreamHandler(
306+ JobArtifactServiceUploadJobArtifactBlockProcedure,
307+ svc.UploadJobArtifactBlock,
308+ connect.WithSchema(jobArtifactServiceMethods.ByName("UploadJobArtifactBlock")),
309+ connect.WithHandlerOptions(opts...),
310+ )
311+ jobArtifactServiceCommitJobArtifactHandler := connect.NewUnaryHandler(
312+ JobArtifactServiceCommitJobArtifactProcedure,
313+ svc.CommitJobArtifact,
314+ connect.WithSchema(jobArtifactServiceMethods.ByName("CommitJobArtifact")),
315+ connect.WithHandlerOptions(opts...),
316+ )
317+ jobArtifactServiceFinalizeJobArtifactHandler := connect.NewUnaryHandler(
318+ JobArtifactServiceFinalizeJobArtifactProcedure,
319+ svc.FinalizeJobArtifact,
320+ connect.WithSchema(jobArtifactServiceMethods.ByName("FinalizeJobArtifact")),
321+ connect.WithHandlerOptions(opts...),
322+ )
323+ jobArtifactServiceListJobArtifactsHandler := connect.NewUnaryHandler(
324+ JobArtifactServiceListJobArtifactsProcedure,
325+ svc.ListJobArtifacts,
326+ connect.WithSchema(jobArtifactServiceMethods.ByName("ListJobArtifacts")),
327+ connect.WithHandlerOptions(opts...),
328+ )
329+ jobArtifactServiceDownloadJobArtifactHandler := connect.NewServerStreamHandler(
330+ JobArtifactServiceDownloadJobArtifactProcedure,
331+ svc.DownloadJobArtifact,
332+ connect.WithSchema(jobArtifactServiceMethods.ByName("DownloadJobArtifact")),
333+ connect.WithHandlerOptions(opts...),
334+ )
335+ jobArtifactServiceDeleteJobArtifactHandler := connect.NewUnaryHandler(
336+ JobArtifactServiceDeleteJobArtifactProcedure,
337+ svc.DeleteJobArtifact,
338+ connect.WithSchema(jobArtifactServiceMethods.ByName("DeleteJobArtifact")),
339+ connect.WithHandlerOptions(opts...),
340+ )
341+ return "/ermite.JobArtifactService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
342+ switch r.URL.Path {
343+ case JobArtifactServiceCreateJobArtifactProcedure:
344+ jobArtifactServiceCreateJobArtifactHandler.ServeHTTP(w, r)
345+ case JobArtifactServiceUploadJobArtifactBlockProcedure:
346+ jobArtifactServiceUploadJobArtifactBlockHandler.ServeHTTP(w, r)
347+ case JobArtifactServiceCommitJobArtifactProcedure:
348+ jobArtifactServiceCommitJobArtifactHandler.ServeHTTP(w, r)
349+ case JobArtifactServiceFinalizeJobArtifactProcedure:
350+ jobArtifactServiceFinalizeJobArtifactHandler.ServeHTTP(w, r)
351+ case JobArtifactServiceListJobArtifactsProcedure:
352+ jobArtifactServiceListJobArtifactsHandler.ServeHTTP(w, r)
353+ case JobArtifactServiceDownloadJobArtifactProcedure:
354+ jobArtifactServiceDownloadJobArtifactHandler.ServeHTTP(w, r)
355+ case JobArtifactServiceDeleteJobArtifactProcedure:
356+ jobArtifactServiceDeleteJobArtifactHandler.ServeHTTP(w, r)
357+ default:
358+ http.NotFound(w, r)
359+ }
360+ })
361+}
362+
363+// UnimplementedJobArtifactServiceHandler returns CodeUnimplemented from all methods.
364+type UnimplementedJobArtifactServiceHandler struct{}
365+
366+func (UnimplementedJobArtifactServiceHandler) CreateJobArtifact(context.Context, *connect.Request[ermite.CreateJobArtifactRequest]) (*connect.Response[ermite.CreateJobArtifactResponse], error) {
367+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.CreateJobArtifact is not implemented"))
368+}
369+
370+func (UnimplementedJobArtifactServiceHandler) UploadJobArtifactBlock(context.Context, *connect.ClientStream[ermite.UploadJobArtifactBlockRequest]) (*connect.Response[ermite.UploadJobArtifactBlockResponse], error) {
371+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.UploadJobArtifactBlock is not implemented"))
372+}
373+
374+func (UnimplementedJobArtifactServiceHandler) CommitJobArtifact(context.Context, *connect.Request[ermite.CommitJobArtifactRequest]) (*connect.Response[ermite.CommitJobArtifactResponse], error) {
375+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.CommitJobArtifact is not implemented"))
376+}
377+
378+func (UnimplementedJobArtifactServiceHandler) FinalizeJobArtifact(context.Context, *connect.Request[ermite.FinalizeJobArtifactRequest]) (*connect.Response[ermite.FinalizeJobArtifactResponse], error) {
379+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.FinalizeJobArtifact is not implemented"))
380+}
381+
382+func (UnimplementedJobArtifactServiceHandler) ListJobArtifacts(context.Context, *connect.Request[ermite.ListJobArtifactsRequest]) (*connect.Response[ermite.ListJobArtifactsResponse], error) {
383+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.ListJobArtifacts is not implemented"))
384+}
385+
386+func (UnimplementedJobArtifactServiceHandler) DownloadJobArtifact(context.Context, *connect.Request[ermite.DownloadJobArtifactRequest], *connect.ServerStream[ermite.DownloadJobArtifactResponse]) error {
387+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.DownloadJobArtifact is not implemented"))
388+}
389+
390+func (UnimplementedJobArtifactServiceHandler) DeleteJobArtifact(context.Context, *connect.Request[ermite.DeleteJobArtifactRequest]) (*connect.Response[ermite.DeleteJobArtifactResponse], error) {
391+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.JobArtifactService.DeleteJobArtifact is not implemented"))
392+}
393+
394+// ArtifactServiceClient is a client for the ermite.ArtifactService service.
395+type ArtifactServiceClient interface {
396+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
397+ // artifacts of the repository use.
398+ ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error)
399+ // DownloadArtifact streams the content of an artifact, as
400+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
401+ // artifact is not an artifact of the repository, and out_of_range if offset
402+ // is beyond its size.
403+ DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadArtifactResponse], error)
404+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
405+ // artifact of the repository.
406+ DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error)
407+}
408+
409+// NewArtifactServiceClient constructs a client for the ermite.ArtifactService service. By default,
410+// it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and
411+// sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC()
412+// or connect.WithGRPCWeb() options.
413+//
414+// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
415+// http://api.acme.com or https://acme.com/grpc).
416+func NewArtifactServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ArtifactServiceClient {
417+ baseURL = strings.TrimRight(baseURL, "/")
418+ artifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("ArtifactService").Methods()
419+ return &artifactServiceClient{
420+ listArtifacts: connect.NewClient[ermite.ListArtifactsRequest, ermite.ListArtifactsResponse](
421+ httpClient,
422+ baseURL+ArtifactServiceListArtifactsProcedure,
423+ connect.WithSchema(artifactServiceMethods.ByName("ListArtifacts")),
424+ connect.WithClientOptions(opts...),
425+ ),
426+ downloadArtifact: connect.NewClient[ermite.DownloadArtifactRequest, ermite.DownloadArtifactResponse](
427+ httpClient,
428+ baseURL+ArtifactServiceDownloadArtifactProcedure,
429+ connect.WithSchema(artifactServiceMethods.ByName("DownloadArtifact")),
430+ connect.WithClientOptions(opts...),
431+ ),
432+ deleteArtifact: connect.NewClient[ermite.DeleteArtifactRequest, ermite.DeleteArtifactResponse](
433+ httpClient,
434+ baseURL+ArtifactServiceDeleteArtifactProcedure,
435+ connect.WithSchema(artifactServiceMethods.ByName("DeleteArtifact")),
436+ connect.WithClientOptions(opts...),
437+ ),
438+ }
439+}
440+
441+// artifactServiceClient implements ArtifactServiceClient.
442+type artifactServiceClient struct {
443+ listArtifacts *connect.Client[ermite.ListArtifactsRequest, ermite.ListArtifactsResponse]
444+ downloadArtifact *connect.Client[ermite.DownloadArtifactRequest, ermite.DownloadArtifactResponse]
445+ deleteArtifact *connect.Client[ermite.DeleteArtifactRequest, ermite.DeleteArtifactResponse]
446+}
447+
448+// ListArtifacts calls ermite.ArtifactService.ListArtifacts.
449+func (c *artifactServiceClient) ListArtifacts(ctx context.Context, req *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error) {
450+ return c.listArtifacts.CallUnary(ctx, req)
451+}
452+
453+// DownloadArtifact calls ermite.ArtifactService.DownloadArtifact.
454+func (c *artifactServiceClient) DownloadArtifact(ctx context.Context, req *connect.Request[ermite.DownloadArtifactRequest]) (*connect.ServerStreamForClient[ermite.DownloadArtifactResponse], error) {
455+ return c.downloadArtifact.CallServerStream(ctx, req)
456+}
457+
458+// DeleteArtifact calls ermite.ArtifactService.DeleteArtifact.
459+func (c *artifactServiceClient) DeleteArtifact(ctx context.Context, req *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error) {
460+ return c.deleteArtifact.CallUnary(ctx, req)
461+}
462+
463+// ArtifactServiceHandler is an implementation of the ermite.ArtifactService service.
464+type ArtifactServiceHandler interface {
465+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
466+ // artifacts of the repository use.
467+ ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error)
468+ // DownloadArtifact streams the content of an artifact, as
469+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
470+ // artifact is not an artifact of the repository, and out_of_range if offset
471+ // is beyond its size.
472+ DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest], *connect.ServerStream[ermite.DownloadArtifactResponse]) error
473+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
474+ // artifact of the repository.
475+ DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error)
476+}
477+
478+// NewArtifactServiceHandler builds an HTTP handler from the service implementation. It returns the
479+// path on which to mount the handler and the handler itself.
480+//
481+// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
482+// and JSON codecs. They also support gzip compression.
483+func NewArtifactServiceHandler(svc ArtifactServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
484+ artifactServiceMethods := ermite.File_ermite_artifact_proto.Services().ByName("ArtifactService").Methods()
485+ artifactServiceListArtifactsHandler := connect.NewUnaryHandler(
486+ ArtifactServiceListArtifactsProcedure,
487+ svc.ListArtifacts,
488+ connect.WithSchema(artifactServiceMethods.ByName("ListArtifacts")),
489+ connect.WithHandlerOptions(opts...),
490+ )
491+ artifactServiceDownloadArtifactHandler := connect.NewServerStreamHandler(
492+ ArtifactServiceDownloadArtifactProcedure,
493+ svc.DownloadArtifact,
494+ connect.WithSchema(artifactServiceMethods.ByName("DownloadArtifact")),
495+ connect.WithHandlerOptions(opts...),
496+ )
497+ artifactServiceDeleteArtifactHandler := connect.NewUnaryHandler(
498+ ArtifactServiceDeleteArtifactProcedure,
499+ svc.DeleteArtifact,
500+ connect.WithSchema(artifactServiceMethods.ByName("DeleteArtifact")),
501+ connect.WithHandlerOptions(opts...),
502+ )
503+ return "/ermite.ArtifactService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
504+ switch r.URL.Path {
505+ case ArtifactServiceListArtifactsProcedure:
506+ artifactServiceListArtifactsHandler.ServeHTTP(w, r)
507+ case ArtifactServiceDownloadArtifactProcedure:
508+ artifactServiceDownloadArtifactHandler.ServeHTTP(w, r)
509+ case ArtifactServiceDeleteArtifactProcedure:
510+ artifactServiceDeleteArtifactHandler.ServeHTTP(w, r)
511+ default:
512+ http.NotFound(w, r)
513+ }
514+ })
515+}
516+
517+// UnimplementedArtifactServiceHandler returns CodeUnimplemented from all methods.
518+type UnimplementedArtifactServiceHandler struct{}
519+
520+func (UnimplementedArtifactServiceHandler) ListArtifacts(context.Context, *connect.Request[ermite.ListArtifactsRequest]) (*connect.Response[ermite.ListArtifactsResponse], error) {
521+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.ListArtifacts is not implemented"))
522+}
523+
524+func (UnimplementedArtifactServiceHandler) DownloadArtifact(context.Context, *connect.Request[ermite.DownloadArtifactRequest], *connect.ServerStream[ermite.DownloadArtifactResponse]) error {
525+ return connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.DownloadArtifact is not implemented"))
526+}
527+
528+func (UnimplementedArtifactServiceHandler) DeleteArtifact(context.Context, *connect.Request[ermite.DeleteArtifactRequest]) (*connect.Response[ermite.DeleteArtifactResponse], error) {
529+ return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ermite.ArtifactService.DeleteArtifact is not implemented"))
530+}
M gen/ermite/server.pb.go +2 -1 generated file: collapsed
M gen_test.go +10 -0
@@ -78,6 +78,16 @@ func TestProcedures(t *testing.T) {
7878 {ermiteconnect.EnvironmentServiceCreateEnvironmentProcedure, "/ermite.EnvironmentService/CreateEnvironment"},
7979 {ermiteconnect.EnvironmentServiceListEnvironmentsProcedure, "/ermite.EnvironmentService/ListEnvironments"},
8080 {ermiteconnect.EnvironmentServiceDeleteEnvironmentProcedure, "/ermite.EnvironmentService/DeleteEnvironment"},
81+ {ermiteconnect.JobArtifactServiceCreateJobArtifactProcedure, "/ermite.JobArtifactService/CreateJobArtifact"},
82+ {ermiteconnect.JobArtifactServiceUploadJobArtifactBlockProcedure, "/ermite.JobArtifactService/UploadJobArtifactBlock"},
83+ {ermiteconnect.JobArtifactServiceCommitJobArtifactProcedure, "/ermite.JobArtifactService/CommitJobArtifact"},
84+ {ermiteconnect.JobArtifactServiceFinalizeJobArtifactProcedure, "/ermite.JobArtifactService/FinalizeJobArtifact"},
85+ {ermiteconnect.JobArtifactServiceListJobArtifactsProcedure, "/ermite.JobArtifactService/ListJobArtifacts"},
86+ {ermiteconnect.JobArtifactServiceDownloadJobArtifactProcedure, "/ermite.JobArtifactService/DownloadJobArtifact"},
87+ {ermiteconnect.JobArtifactServiceDeleteJobArtifactProcedure, "/ermite.JobArtifactService/DeleteJobArtifact"},
88+ {ermiteconnect.ArtifactServiceListArtifactsProcedure, "/ermite.ArtifactService/ListArtifacts"},
89+ {ermiteconnect.ArtifactServiceDownloadArtifactProcedure, "/ermite.ArtifactService/DownloadArtifact"},
90+ {ermiteconnect.ArtifactServiceDeleteArtifactProcedure, "/ermite.ArtifactService/DeleteArtifact"},
8191 }
8292 for _, tt := range tests {
8393 if tt.got != tt.want {
@@ -78,6 +78,16 @@ func TestProcedures(t *testing.T) {
78 {ermiteconnect.EnvironmentServiceCreateEnvironmentProcedure, "/ermite.EnvironmentService/CreateEnvironment"},78 {ermiteconnect.EnvironmentServiceCreateEnvironmentProcedure, "/ermite.EnvironmentService/CreateEnvironment"},
79 {ermiteconnect.EnvironmentServiceListEnvironmentsProcedure, "/ermite.EnvironmentService/ListEnvironments"},79 {ermiteconnect.EnvironmentServiceListEnvironmentsProcedure, "/ermite.EnvironmentService/ListEnvironments"},
80 {ermiteconnect.EnvironmentServiceDeleteEnvironmentProcedure, "/ermite.EnvironmentService/DeleteEnvironment"},80 {ermiteconnect.EnvironmentServiceDeleteEnvironmentProcedure, "/ermite.EnvironmentService/DeleteEnvironment"},
81+ {ermiteconnect.JobArtifactServiceCreateJobArtifactProcedure, "/ermite.JobArtifactService/CreateJobArtifact"},
82+ {ermiteconnect.JobArtifactServiceUploadJobArtifactBlockProcedure, "/ermite.JobArtifactService/UploadJobArtifactBlock"},
83+ {ermiteconnect.JobArtifactServiceCommitJobArtifactProcedure, "/ermite.JobArtifactService/CommitJobArtifact"},
84+ {ermiteconnect.JobArtifactServiceFinalizeJobArtifactProcedure, "/ermite.JobArtifactService/FinalizeJobArtifact"},
85+ {ermiteconnect.JobArtifactServiceListJobArtifactsProcedure, "/ermite.JobArtifactService/ListJobArtifacts"},
86+ {ermiteconnect.JobArtifactServiceDownloadJobArtifactProcedure, "/ermite.JobArtifactService/DownloadJobArtifact"},
87+ {ermiteconnect.JobArtifactServiceDeleteJobArtifactProcedure, "/ermite.JobArtifactService/DeleteJobArtifact"},
88+ {ermiteconnect.ArtifactServiceListArtifactsProcedure, "/ermite.ArtifactService/ListArtifacts"},
89+ {ermiteconnect.ArtifactServiceDownloadArtifactProcedure, "/ermite.ArtifactService/DownloadArtifact"},
90+ {ermiteconnect.ArtifactServiceDeleteArtifactProcedure, "/ermite.ArtifactService/DeleteArtifact"},
81 }91 }
82 for _, tt := range tests {92 for _, tt := range tests {
83 if tt.got != tt.want {93 if tt.got != tt.want {
A proto/ermite/artifact.proto +350 -0
@@ -0,0 +1,350 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Artifact is a file that a job of a run uploaded with actions/upload-artifact
10+// (artifacts v4): in most cases a zip archive, or a single file uploaded as is
11+// ("archive: false"). It belongs to a run, not to one attempt: every job of the
12+// run, in any attempt, sees the artifacts of the run. Only finalized artifacts
13+// are described; an upload in progress is invisible.
14+message Artifact {
15+ // Id identifies the artifact on the server: unique across repositories and
16+ // runs, never reused, and higher for a later artifact. It is GitHub's
17+ // "artifact id" (databaseId), the id of the REST API.
18+ int64 id = 1;
19+ // Repo is the name of the repository of the run.
20+ string repo = 2;
21+ // RunId is the run the artifact belongs to.
22+ int64 run_id = 3;
23+ // Attempt is the attempt of the run whose job uploaded it.
24+ int32 attempt = 4;
25+ // JobId is the Job.job_id of the job that uploaded it.
26+ string job_id = 5;
27+ // Name is the name of the artifact, unique among the artifacts of the run:
28+ // 1 to 256 characters of valid UTF-8, without control characters, '"', ':',
29+ // '<', '>', '|', '*', '?', '\' or '/' (the characters @actions/artifact
30+ // refuses).
31+ string name = 6;
32+ // Size is the number of bytes of the content.
33+ int64 size = 7;
34+ // Digest is the SHA-256 of the content, "sha256:" and 64 lowercase
35+ // hexadecimal characters, as GitHub gives it.
36+ string digest = 8;
37+ // MediaType is the media type of the content: "application/zip" for an
38+ // archive, the type the uploader gave for a file uploaded as is.
39+ string media_type = 9;
40+ // CreatedAt is when the upload began.
41+ google.protobuf.Timestamp created_at = 10;
42+ // ExpiresAt is when the server deletes the artifact (see
43+ // CreateJobArtifactRequest.expires_at).
44+ google.protobuf.Timestamp expires_at = 11;
45+}
46+
47+// JobArtifactService is the artifacts side of a CI runner: what ermite-runner
48+// calls when the job's code uploads or downloads artifacts through the
49+// results service the runner serves in the sandbox (Twirp
50+// github.actions.results.api.v1.ArtifactService and Azure block blobs). The
51+// runner translates that protocol; the server stores the content, enforces the
52+// limits and decides what the job may see. It is not for people: owners use
53+// ArtifactService.
54+//
55+// Every RPC needs the job token of the job ("Authorization: Bearer
56+// ermitejob_..."), and job_id must be the job of the token, with the errors of
57+// RunnerService (unauthenticated, permission_denied, and failed_precondition
58+// with a JobEnded detail once the job has ended). The run is always the one of
59+// the token: no request names a run, so a job can only reach the artifacts of
60+// its own run, and the run and job ids that the job's code puts in its Twirp
61+// requests are never passed on.
62+//
63+// An upload goes: CreateJobArtifact (a pending artifact and its id), any number
64+// of UploadJobArtifactBlock (in any order and concurrently), one
65+// CommitJobArtifact (the order of the blocks: the content), then
66+// FinalizeJobArtifact (the artifact becomes visible). Every step is safe to
67+// retry after a network error. A pending artifact that is not finalized when
68+// its job ends is deleted with its blocks.
69+//
70+// Limits are settings of the server: the size of one artifact, the space of all
71+// the artifacts of a repository (pending uploads included) and the longest
72+// retention. A call that would go over a size limit fails with
73+// resource_exhausted and a message that names the limit; nothing of the call
74+// is kept.
75+//
76+// Servers that implement this service and ArtifactService list "ci.artifacts"
77+// in GetVersionResponse.features; others answer unimplemented. A runner without
78+// that feature serves no results service, and artifact actions fail as on a
79+// GitHub Enterprise Server without artifacts v4.
80+service JobArtifactService {
81+ // CreateJobArtifact begins the upload of an artifact of the job's run and
82+ // returns its id. Fails with invalid_argument if the name or expires_at break
83+ // a rule, already_exists if an artifact of that name was finalized by a job
84+ // of the same attempt of the run (the uploader deletes it first to replace
85+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
86+ // repository already use all their space. A pending artifact of the same
87+ // job and name is discarded: a new create is a new upload.
88+ rpc CreateJobArtifact(CreateJobArtifactRequest) returns (CreateJobArtifactResponse);
89+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
90+ // client stream: the first message names the job, the artifact and the
91+ // block, every message may carry data, and the block is the data of all the
92+ // messages in order. The block is stored when the client closes the stream
93+ // and the server answers; a stream that breaks or fails stores nothing.
94+ // Storing a block id again replaces the block, so a retry is safe. Blocks
95+ // that the commit does not name are dropped.
96+ //
97+ // Fails with not_found if the artifact is not a pending artifact of this job,
98+ // failed_precondition if it is already committed, invalid_argument if a rule
99+ // of the messages is broken, and resource_exhausted if the blocks of the
100+ // artifact would exceed the size of one artifact or the space of the
101+ // repository.
102+ rpc UploadJobArtifactBlock(stream UploadJobArtifactBlockRequest) returns (UploadJobArtifactBlockResponse);
103+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
104+ // in that order (Azure's Put Block List). An empty list is an empty content
105+ // (a 0-byte upload). The server then knows the size and the digest, and
106+ // drops the blocks. A repeat of the same call after a success returns the
107+ // same result; a different list on a committed artifact is
108+ // failed_precondition. Fails with not_found if the artifact is not a pending
109+ // artifact of this job, and invalid_argument if a block id was never
110+ // uploaded or the list has more than 50,000 ids.
111+ rpc CommitJobArtifact(CommitJobArtifactRequest) returns (CommitJobArtifactResponse);
112+ // FinalizeJobArtifact makes the latest committed artifact of the job with
113+ // that name visible to the run, and returns it. An artifact of the same name
114+ // from an earlier attempt of the run is deleted at the same moment (a re-run
115+ // replaces what the first attempt uploaded). A repeat after a success
116+ // returns the same artifact. Fails with not_found if the job has no pending
117+ // artifact of that name, failed_precondition if it is not committed,
118+ // invalid_argument if digest is set and differs from the content, and
119+ // already_exists if a job of the same attempt finalized an artifact of that
120+ // name in the meantime.
121+ rpc FinalizeJobArtifact(FinalizeJobArtifactRequest) returns (FinalizeJobArtifactResponse);
122+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
123+ // all attempts, by id. An empty list is not an error.
124+ rpc ListJobArtifacts(ListJobArtifactsRequest) returns (ListJobArtifactsResponse);
125+ // DownloadJobArtifact streams the content of an artifact of the job's run.
126+ // The first message carries the artifact, then the chunks follow in order
127+ // from offset. A client that loses the stream calls again with the offset
128+ // after the last byte it received. Fails with not_found if the artifact is
129+ // not a finalized artifact of the run (or has expired), and out_of_range if
130+ // offset is beyond its size.
131+ rpc DownloadJobArtifact(DownloadJobArtifactRequest) returns (stream DownloadJobArtifactResponse);
132+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
133+ // run (upload-artifact's "overwrite", and its merge action's
134+ // "delete-merged"). Fails with not_found if there is none.
135+ rpc DeleteJobArtifact(DeleteJobArtifactRequest) returns (DeleteJobArtifactResponse);
136+}
137+
138+// CreateJobArtifactRequest begins an upload.
139+message CreateJobArtifactRequest {
140+ // JobId is the Job.job_id. It must be the job of the token.
141+ string job_id = 1;
142+ // Name is the name of the artifact, see Artifact.name.
143+ string name = 2;
144+ // MediaType is the media type of a file uploaded as is (the toolkit's
145+ // mime_type), at most 255 characters. Empty means "application/zip".
146+ string media_type = 3;
147+ // ExpiresAt is when the artifact should be deleted (the toolkit's
148+ // expires_at, from "retention-days"). Unset means the default retention of
149+ // the server. The server keeps it between one day from now and its longest
150+ // retention, and returns the time it kept.
151+ google.protobuf.Timestamp expires_at = 4;
152+}
153+
154+// CreateJobArtifactResponse identifies the pending artifact.
155+message CreateJobArtifactResponse {
156+ // ArtifactId is the id the artifact will have once finalized (Artifact.id).
157+ int64 artifact_id = 1;
158+ // ExpiresAt is the expiry the server kept.
159+ google.protobuf.Timestamp expires_at = 2;
160+}
161+
162+// UploadJobArtifactBlockRequest is one message of the stream of a block.
163+message UploadJobArtifactBlockRequest {
164+ // JobId is the Job.job_id, in the first message only. It must be the job of
165+ // the token.
166+ string job_id = 1;
167+ // ArtifactId is the CreateJobArtifactResponse.artifact_id, in the first
168+ // message only.
169+ int64 artifact_id = 2;
170+ // BlockId identifies the block within the artifact: 1 to 64 bytes (Azure's
171+ // block id, decoded from base64), in the first message only.
172+ bytes block_id = 3;
173+ // Data is the next part of the block, at most 1 MiB (1,048,576 bytes). Any
174+ // message may have none.
175+ bytes data = 4;
176+}
177+
178+// UploadJobArtifactBlockResponse confirms a stored block.
179+message UploadJobArtifactBlockResponse {
180+ // Size is the number of bytes of the block as stored.
181+ int64 size = 1;
182+}
183+
184+// CommitJobArtifactRequest sets the content of a pending artifact.
185+message CommitJobArtifactRequest {
186+ // JobId is the Job.job_id. It must be the job of the token.
187+ string job_id = 1;
188+ // ArtifactId is the CreateJobArtifactResponse.artifact_id.
189+ int64 artifact_id = 2;
190+ // BlockIds are the blocks of the content, in order, each one as given to
191+ // UploadJobArtifactBlock. At most 50,000; the same id may appear more than
192+ // once.
193+ repeated bytes block_ids = 3;
194+}
195+
196+// CommitJobArtifactResponse describes the committed content.
197+message CommitJobArtifactResponse {
198+ // Size is the number of bytes of the content.
199+ int64 size = 1;
200+ // Digest is the SHA-256 of the content, see Artifact.digest.
201+ string digest = 2;
202+}
203+
204+// FinalizeJobArtifactRequest ends an upload.
205+message FinalizeJobArtifactRequest {
206+ // JobId is the Job.job_id. It must be the job of the token.
207+ string job_id = 1;
208+ // Name is the name given to CreateJobArtifact. The toolkit finalizes by name.
209+ string name = 2;
210+ // Size is the size the uploader counted. Informational: the server keeps the
211+ // size of the content it stored, and only logs a difference.
212+ int64 size = 3;
213+ // Digest is the digest the uploader computed ("sha256:<hex>"), or empty.
214+ // When set it must be the digest of the content.
215+ string digest = 4;
216+}
217+
218+// FinalizeJobArtifactResponse describes the artifact now visible.
219+message FinalizeJobArtifactResponse {
220+ // Artifact is the finalized artifact.
221+ Artifact artifact = 1;
222+}
223+
224+// ListJobArtifactsRequest selects artifacts of the job's run.
225+message ListJobArtifactsRequest {
226+ // JobId is the Job.job_id. It must be the job of the token.
227+ string job_id = 1;
228+ // Name keeps only the artifact of that name. Empty means every name.
229+ string name = 2;
230+ // ArtifactId keeps only the artifact of that id. 0 means every id.
231+ int64 artifact_id = 3;
232+}
233+
234+// ListJobArtifactsResponse lists artifacts of the job's run.
235+message ListJobArtifactsResponse {
236+ // Artifacts are the artifacts, by id.
237+ repeated Artifact artifacts = 1;
238+}
239+
240+// DownloadJobArtifactRequest selects the content of an artifact.
241+message DownloadJobArtifactRequest {
242+ // JobId is the Job.job_id. It must be the job of the token.
243+ string job_id = 1;
244+ // ArtifactId is the Artifact.id of an artifact of the job's run.
245+ int64 artifact_id = 2;
246+ // Offset is the first byte to send, from 0 to the size of the artifact.
247+ int64 offset = 3;
248+}
249+
250+// DownloadJobArtifactResponse is one message of the content stream.
251+message DownloadJobArtifactResponse {
252+ // Artifact describes the artifact. Set in the first message of the stream
253+ // only.
254+ Artifact artifact = 1;
255+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
256+ // message may have an empty chunk. The chunks of a stream add up to the size
257+ // of the artifact minus the offset.
258+ bytes chunk = 2;
259+}
260+
261+// DeleteJobArtifactRequest names the artifact to delete.
262+message DeleteJobArtifactRequest {
263+ // JobId is the Job.job_id. It must be the job of the token.
264+ string job_id = 1;
265+ // Name is the name of a finalized artifact of the job's run.
266+ string name = 2;
267+}
268+
269+// DeleteJobArtifactResponse identifies the deleted artifact.
270+message DeleteJobArtifactResponse {
271+ // ArtifactId is the Artifact.id of the artifact that was deleted.
272+ int64 artifact_id = 1;
273+}
274+
275+// ArtifactService lets people list, download and delete the artifacts of the
276+// runs of a repository (run page, `ermite run download`). Listing and
277+// downloading need a signed-in caller with read access to the repository (the
278+// repo:read scope for a token), even for a public repository: like GitHub,
279+// artifacts are not served anonymously. Deleting needs the ci:write scope. A
280+// repository or a run that does not exist or that the caller cannot read gives
281+// not_found.
282+//
283+// Artifacts are deleted when they expire (Artifact.expires_at), with their run
284+// (run retention) and with their repository.
285+//
286+// Only servers with the feature "ci.artifacts" implement it (unimplemented
287+// otherwise).
288+service ArtifactService {
289+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
290+ // artifacts of the repository use.
291+ rpc ListArtifacts(ListArtifactsRequest) returns (ListArtifactsResponse);
292+ // DownloadArtifact streams the content of an artifact, as
293+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
294+ // artifact is not an artifact of the repository, and out_of_range if offset
295+ // is beyond its size.
296+ rpc DownloadArtifact(DownloadArtifactRequest) returns (stream DownloadArtifactResponse);
297+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
298+ // artifact of the repository.
299+ rpc DeleteArtifact(DeleteArtifactRequest) returns (DeleteArtifactResponse);
300+}
301+
302+// ListArtifactsRequest selects the artifacts of a run.
303+message ListArtifactsRequest {
304+ // Repo is the repository name.
305+ string repo = 1;
306+ // RunId is the run.
307+ int64 run_id = 2;
308+}
309+
310+// ListArtifactsResponse lists the artifacts of a run.
311+message ListArtifactsResponse {
312+ // Artifacts are the artifacts of the run, all attempts, by id.
313+ repeated Artifact artifacts = 1;
314+ // UsedBytes is the space that all the artifacts of the repository use,
315+ // uploads in progress included.
316+ int64 used_bytes = 2;
317+ // QuotaBytes is the space the artifacts of the repository may use.
318+ int64 quota_bytes = 3;
319+}
320+
321+// DownloadArtifactRequest selects the content of an artifact.
322+message DownloadArtifactRequest {
323+ // Repo is the repository name.
324+ string repo = 1;
325+ // ArtifactId is the Artifact.id.
326+ int64 artifact_id = 2;
327+ // Offset is the first byte to send, from 0 to the size of the artifact.
328+ int64 offset = 3;
329+}
330+
331+// DownloadArtifactResponse is one message of the content stream.
332+message DownloadArtifactResponse {
333+ // Artifact describes the artifact. Set in the first message of the stream
334+ // only.
335+ Artifact artifact = 1;
336+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
337+ // message may have an empty chunk.
338+ bytes chunk = 2;
339+}
340+
341+// DeleteArtifactRequest names the artifact to delete.
342+message DeleteArtifactRequest {
343+ // Repo is the repository name.
344+ string repo = 1;
345+ // ArtifactId is the Artifact.id.
346+ int64 artifact_id = 2;
347+}
348+
349+// DeleteArtifactResponse is empty.
350+message DeleteArtifactResponse {}
@@ -0,0 +1,350 @@
1+// SPDX-License-Identifier: MIT
2+
3+syntax = "proto3";
4+
5+package ermite;
6+
7+import "google/protobuf/timestamp.proto";
8+
9+// Artifact is a file that a job of a run uploaded with actions/upload-artifact
10+// (artifacts v4): in most cases a zip archive, or a single file uploaded as is
11+// ("archive: false"). It belongs to a run, not to one attempt: every job of the
12+// run, in any attempt, sees the artifacts of the run. Only finalized artifacts
13+// are described; an upload in progress is invisible.
14+message Artifact {
15+ // Id identifies the artifact on the server: unique across repositories and
16+ // runs, never reused, and higher for a later artifact. It is GitHub's
17+ // "artifact id" (databaseId), the id of the REST API.
18+ int64 id = 1;
19+ // Repo is the name of the repository of the run.
20+ string repo = 2;
21+ // RunId is the run the artifact belongs to.
22+ int64 run_id = 3;
23+ // Attempt is the attempt of the run whose job uploaded it.
24+ int32 attempt = 4;
25+ // JobId is the Job.job_id of the job that uploaded it.
26+ string job_id = 5;
27+ // Name is the name of the artifact, unique among the artifacts of the run:
28+ // 1 to 256 characters of valid UTF-8, without control characters, '"', ':',
29+ // '<', '>', '|', '*', '?', '\' or '/' (the characters @actions/artifact
30+ // refuses).
31+ string name = 6;
32+ // Size is the number of bytes of the content.
33+ int64 size = 7;
34+ // Digest is the SHA-256 of the content, "sha256:" and 64 lowercase
35+ // hexadecimal characters, as GitHub gives it.
36+ string digest = 8;
37+ // MediaType is the media type of the content: "application/zip" for an
38+ // archive, the type the uploader gave for a file uploaded as is.
39+ string media_type = 9;
40+ // CreatedAt is when the upload began.
41+ google.protobuf.Timestamp created_at = 10;
42+ // ExpiresAt is when the server deletes the artifact (see
43+ // CreateJobArtifactRequest.expires_at).
44+ google.protobuf.Timestamp expires_at = 11;
45+}
46+
47+// JobArtifactService is the artifacts side of a CI runner: what ermite-runner
48+// calls when the job's code uploads or downloads artifacts through the
49+// results service the runner serves in the sandbox (Twirp
50+// github.actions.results.api.v1.ArtifactService and Azure block blobs). The
51+// runner translates that protocol; the server stores the content, enforces the
52+// limits and decides what the job may see. It is not for people: owners use
53+// ArtifactService.
54+//
55+// Every RPC needs the job token of the job ("Authorization: Bearer
56+// ermitejob_..."), and job_id must be the job of the token, with the errors of
57+// RunnerService (unauthenticated, permission_denied, and failed_precondition
58+// with a JobEnded detail once the job has ended). The run is always the one of
59+// the token: no request names a run, so a job can only reach the artifacts of
60+// its own run, and the run and job ids that the job's code puts in its Twirp
61+// requests are never passed on.
62+//
63+// An upload goes: CreateJobArtifact (a pending artifact and its id), any number
64+// of UploadJobArtifactBlock (in any order and concurrently), one
65+// CommitJobArtifact (the order of the blocks: the content), then
66+// FinalizeJobArtifact (the artifact becomes visible). Every step is safe to
67+// retry after a network error. A pending artifact that is not finalized when
68+// its job ends is deleted with its blocks.
69+//
70+// Limits are settings of the server: the size of one artifact, the space of all
71+// the artifacts of a repository (pending uploads included) and the longest
72+// retention. A call that would go over a size limit fails with
73+// resource_exhausted and a message that names the limit; nothing of the call
74+// is kept.
75+//
76+// Servers that implement this service and ArtifactService list "ci.artifacts"
77+// in GetVersionResponse.features; others answer unimplemented. A runner without
78+// that feature serves no results service, and artifact actions fail as on a
79+// GitHub Enterprise Server without artifacts v4.
80+service JobArtifactService {
81+ // CreateJobArtifact begins the upload of an artifact of the job's run and
82+ // returns its id. Fails with invalid_argument if the name or expires_at break
83+ // a rule, already_exists if an artifact of that name was finalized by a job
84+ // of the same attempt of the run (the uploader deletes it first to replace
85+ // it: DeleteJobArtifact), and resource_exhausted if the artifacts of the
86+ // repository already use all their space. A pending artifact of the same
87+ // job and name is discarded: a new create is a new upload.
88+ rpc CreateJobArtifact(CreateJobArtifactRequest) returns (CreateJobArtifactResponse);
89+ // UploadJobArtifactBlock stores one block of a pending artifact. It is a
90+ // client stream: the first message names the job, the artifact and the
91+ // block, every message may carry data, and the block is the data of all the
92+ // messages in order. The block is stored when the client closes the stream
93+ // and the server answers; a stream that breaks or fails stores nothing.
94+ // Storing a block id again replaces the block, so a retry is safe. Blocks
95+ // that the commit does not name are dropped.
96+ //
97+ // Fails with not_found if the artifact is not a pending artifact of this job,
98+ // failed_precondition if it is already committed, invalid_argument if a rule
99+ // of the messages is broken, and resource_exhausted if the blocks of the
100+ // artifact would exceed the size of one artifact or the space of the
101+ // repository.
102+ rpc UploadJobArtifactBlock(stream UploadJobArtifactBlockRequest) returns (UploadJobArtifactBlockResponse);
103+ // CommitJobArtifact sets the content of a pending artifact: the blocks named,
104+ // in that order (Azure's Put Block List). An empty list is an empty content
105+ // (a 0-byte upload). The server then knows the size and the digest, and
106+ // drops the blocks. A repeat of the same call after a success returns the
107+ // same result; a different list on a committed artifact is
108+ // failed_precondition. Fails with not_found if the artifact is not a pending
109+ // artifact of this job, and invalid_argument if a block id was never
110+ // uploaded or the list has more than 50,000 ids.
111+ rpc CommitJobArtifact(CommitJobArtifactRequest) returns (CommitJobArtifactResponse);
112+ // FinalizeJobArtifact makes the latest committed artifact of the job with
113+ // that name visible to the run, and returns it. An artifact of the same name
114+ // from an earlier attempt of the run is deleted at the same moment (a re-run
115+ // replaces what the first attempt uploaded). A repeat after a success
116+ // returns the same artifact. Fails with not_found if the job has no pending
117+ // artifact of that name, failed_precondition if it is not committed,
118+ // invalid_argument if digest is set and differs from the content, and
119+ // already_exists if a job of the same attempt finalized an artifact of that
120+ // name in the meantime.
121+ rpc FinalizeJobArtifact(FinalizeJobArtifactRequest) returns (FinalizeJobArtifactResponse);
122+ // ListJobArtifacts lists the finalized, unexpired artifacts of the job's run,
123+ // all attempts, by id. An empty list is not an error.
124+ rpc ListJobArtifacts(ListJobArtifactsRequest) returns (ListJobArtifactsResponse);
125+ // DownloadJobArtifact streams the content of an artifact of the job's run.
126+ // The first message carries the artifact, then the chunks follow in order
127+ // from offset. A client that loses the stream calls again with the offset
128+ // after the last byte it received. Fails with not_found if the artifact is
129+ // not a finalized artifact of the run (or has expired), and out_of_range if
130+ // offset is beyond its size.
131+ rpc DownloadJobArtifact(DownloadJobArtifactRequest) returns (stream DownloadJobArtifactResponse);
132+ // DeleteJobArtifact deletes the finalized artifact of that name of the job's
133+ // run (upload-artifact's "overwrite", and its merge action's
134+ // "delete-merged"). Fails with not_found if there is none.
135+ rpc DeleteJobArtifact(DeleteJobArtifactRequest) returns (DeleteJobArtifactResponse);
136+}
137+
138+// CreateJobArtifactRequest begins an upload.
139+message CreateJobArtifactRequest {
140+ // JobId is the Job.job_id. It must be the job of the token.
141+ string job_id = 1;
142+ // Name is the name of the artifact, see Artifact.name.
143+ string name = 2;
144+ // MediaType is the media type of a file uploaded as is (the toolkit's
145+ // mime_type), at most 255 characters. Empty means "application/zip".
146+ string media_type = 3;
147+ // ExpiresAt is when the artifact should be deleted (the toolkit's
148+ // expires_at, from "retention-days"). Unset means the default retention of
149+ // the server. The server keeps it between one day from now and its longest
150+ // retention, and returns the time it kept.
151+ google.protobuf.Timestamp expires_at = 4;
152+}
153+
154+// CreateJobArtifactResponse identifies the pending artifact.
155+message CreateJobArtifactResponse {
156+ // ArtifactId is the id the artifact will have once finalized (Artifact.id).
157+ int64 artifact_id = 1;
158+ // ExpiresAt is the expiry the server kept.
159+ google.protobuf.Timestamp expires_at = 2;
160+}
161+
162+// UploadJobArtifactBlockRequest is one message of the stream of a block.
163+message UploadJobArtifactBlockRequest {
164+ // JobId is the Job.job_id, in the first message only. It must be the job of
165+ // the token.
166+ string job_id = 1;
167+ // ArtifactId is the CreateJobArtifactResponse.artifact_id, in the first
168+ // message only.
169+ int64 artifact_id = 2;
170+ // BlockId identifies the block within the artifact: 1 to 64 bytes (Azure's
171+ // block id, decoded from base64), in the first message only.
172+ bytes block_id = 3;
173+ // Data is the next part of the block, at most 1 MiB (1,048,576 bytes). Any
174+ // message may have none.
175+ bytes data = 4;
176+}
177+
178+// UploadJobArtifactBlockResponse confirms a stored block.
179+message UploadJobArtifactBlockResponse {
180+ // Size is the number of bytes of the block as stored.
181+ int64 size = 1;
182+}
183+
184+// CommitJobArtifactRequest sets the content of a pending artifact.
185+message CommitJobArtifactRequest {
186+ // JobId is the Job.job_id. It must be the job of the token.
187+ string job_id = 1;
188+ // ArtifactId is the CreateJobArtifactResponse.artifact_id.
189+ int64 artifact_id = 2;
190+ // BlockIds are the blocks of the content, in order, each one as given to
191+ // UploadJobArtifactBlock. At most 50,000; the same id may appear more than
192+ // once.
193+ repeated bytes block_ids = 3;
194+}
195+
196+// CommitJobArtifactResponse describes the committed content.
197+message CommitJobArtifactResponse {
198+ // Size is the number of bytes of the content.
199+ int64 size = 1;
200+ // Digest is the SHA-256 of the content, see Artifact.digest.
201+ string digest = 2;
202+}
203+
204+// FinalizeJobArtifactRequest ends an upload.
205+message FinalizeJobArtifactRequest {
206+ // JobId is the Job.job_id. It must be the job of the token.
207+ string job_id = 1;
208+ // Name is the name given to CreateJobArtifact. The toolkit finalizes by name.
209+ string name = 2;
210+ // Size is the size the uploader counted. Informational: the server keeps the
211+ // size of the content it stored, and only logs a difference.
212+ int64 size = 3;
213+ // Digest is the digest the uploader computed ("sha256:<hex>"), or empty.
214+ // When set it must be the digest of the content.
215+ string digest = 4;
216+}
217+
218+// FinalizeJobArtifactResponse describes the artifact now visible.
219+message FinalizeJobArtifactResponse {
220+ // Artifact is the finalized artifact.
221+ Artifact artifact = 1;
222+}
223+
224+// ListJobArtifactsRequest selects artifacts of the job's run.
225+message ListJobArtifactsRequest {
226+ // JobId is the Job.job_id. It must be the job of the token.
227+ string job_id = 1;
228+ // Name keeps only the artifact of that name. Empty means every name.
229+ string name = 2;
230+ // ArtifactId keeps only the artifact of that id. 0 means every id.
231+ int64 artifact_id = 3;
232+}
233+
234+// ListJobArtifactsResponse lists artifacts of the job's run.
235+message ListJobArtifactsResponse {
236+ // Artifacts are the artifacts, by id.
237+ repeated Artifact artifacts = 1;
238+}
239+
240+// DownloadJobArtifactRequest selects the content of an artifact.
241+message DownloadJobArtifactRequest {
242+ // JobId is the Job.job_id. It must be the job of the token.
243+ string job_id = 1;
244+ // ArtifactId is the Artifact.id of an artifact of the job's run.
245+ int64 artifact_id = 2;
246+ // Offset is the first byte to send, from 0 to the size of the artifact.
247+ int64 offset = 3;
248+}
249+
250+// DownloadJobArtifactResponse is one message of the content stream.
251+message DownloadJobArtifactResponse {
252+ // Artifact describes the artifact. Set in the first message of the stream
253+ // only.
254+ Artifact artifact = 1;
255+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
256+ // message may have an empty chunk. The chunks of a stream add up to the size
257+ // of the artifact minus the offset.
258+ bytes chunk = 2;
259+}
260+
261+// DeleteJobArtifactRequest names the artifact to delete.
262+message DeleteJobArtifactRequest {
263+ // JobId is the Job.job_id. It must be the job of the token.
264+ string job_id = 1;
265+ // Name is the name of a finalized artifact of the job's run.
266+ string name = 2;
267+}
268+
269+// DeleteJobArtifactResponse identifies the deleted artifact.
270+message DeleteJobArtifactResponse {
271+ // ArtifactId is the Artifact.id of the artifact that was deleted.
272+ int64 artifact_id = 1;
273+}
274+
275+// ArtifactService lets people list, download and delete the artifacts of the
276+// runs of a repository (run page, `ermite run download`). Listing and
277+// downloading need a signed-in caller with read access to the repository (the
278+// repo:read scope for a token), even for a public repository: like GitHub,
279+// artifacts are not served anonymously. Deleting needs the ci:write scope. A
280+// repository or a run that does not exist or that the caller cannot read gives
281+// not_found.
282+//
283+// Artifacts are deleted when they expire (Artifact.expires_at), with their run
284+// (run retention) and with their repository.
285+//
286+// Only servers with the feature "ci.artifacts" implement it (unimplemented
287+// otherwise).
288+service ArtifactService {
289+ // ListArtifacts lists the artifacts of a run, by id, with the space that the
290+ // artifacts of the repository use.
291+ rpc ListArtifacts(ListArtifactsRequest) returns (ListArtifactsResponse);
292+ // DownloadArtifact streams the content of an artifact, as
293+ // JobArtifactService.DownloadJobArtifact does. Fails with not_found if the
294+ // artifact is not an artifact of the repository, and out_of_range if offset
295+ // is beyond its size.
296+ rpc DownloadArtifact(DownloadArtifactRequest) returns (stream DownloadArtifactResponse);
297+ // DeleteArtifact deletes an artifact. Fails with not_found if it is not an
298+ // artifact of the repository.
299+ rpc DeleteArtifact(DeleteArtifactRequest) returns (DeleteArtifactResponse);
300+}
301+
302+// ListArtifactsRequest selects the artifacts of a run.
303+message ListArtifactsRequest {
304+ // Repo is the repository name.
305+ string repo = 1;
306+ // RunId is the run.
307+ int64 run_id = 2;
308+}
309+
310+// ListArtifactsResponse lists the artifacts of a run.
311+message ListArtifactsResponse {
312+ // Artifacts are the artifacts of the run, all attempts, by id.
313+ repeated Artifact artifacts = 1;
314+ // UsedBytes is the space that all the artifacts of the repository use,
315+ // uploads in progress included.
316+ int64 used_bytes = 2;
317+ // QuotaBytes is the space the artifacts of the repository may use.
318+ int64 quota_bytes = 3;
319+}
320+
321+// DownloadArtifactRequest selects the content of an artifact.
322+message DownloadArtifactRequest {
323+ // Repo is the repository name.
324+ string repo = 1;
325+ // ArtifactId is the Artifact.id.
326+ int64 artifact_id = 2;
327+ // Offset is the first byte to send, from 0 to the size of the artifact.
328+ int64 offset = 3;
329+}
330+
331+// DownloadArtifactResponse is one message of the content stream.
332+message DownloadArtifactResponse {
333+ // Artifact describes the artifact. Set in the first message of the stream
334+ // only.
335+ Artifact artifact = 1;
336+ // Chunk is the next part of the content, at most 1 MiB, in order. The first
337+ // message may have an empty chunk.
338+ bytes chunk = 2;
339+}
340+
341+// DeleteArtifactRequest names the artifact to delete.
342+message DeleteArtifactRequest {
343+ // Repo is the repository name.
344+ string repo = 1;
345+ // ArtifactId is the Artifact.id.
346+ int64 artifact_id = 2;
347+}
348+
349+// DeleteArtifactResponse is empty.
350+message DeleteArtifactResponse {}
M proto/ermite/server.proto +2 -1
@@ -43,7 +43,8 @@ message GetVersionResponse {
4343 // (SecretService, VariableService and EnvironmentService, and in Job the
4444 // secrets, vars, environment, permissions and trusted fields and Run.trusted),
4545 // "ci.dispatch" (RunService.DispatchWorkflow), "ci.concurrency"
46- // (CI_STATUS_PENDING and RunJob.concurrency_group) and "ci.cache" (Job.cache).
46+ // (CI_STATUS_PENDING and RunJob.concurrency_group), "ci.cache" (Job.cache)
47+ // and "ci.artifacts" (JobArtifactService and ArtifactService).
4748 repeated string features = 2;
4849 }
4950
@@ -43,7 +43,8 @@ message GetVersionResponse {
43 // (SecretService, VariableService and EnvironmentService, and in Job the43 // (SecretService, VariableService and EnvironmentService, and in Job the
44 // secrets, vars, environment, permissions and trusted fields and Run.trusted),44 // secrets, vars, environment, permissions and trusted fields and Run.trusted),
45 // "ci.dispatch" (RunService.DispatchWorkflow), "ci.concurrency"45 // "ci.dispatch" (RunService.DispatchWorkflow), "ci.concurrency"
46- // (CI_STATUS_PENDING and RunJob.concurrency_group) and "ci.cache" (Job.cache).46+ // (CI_STATUS_PENDING and RunJob.concurrency_group), "ci.cache" (Job.cache)
47+ // and "ci.artifacts" (JobArtifactService and ArtifactService).
47 repeated string features = 2;48 repeated string features = 2;
48 }49 }
49 50

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