detached 5278df2

ci_artifact.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package ports
4
5import (
6	"context"
7	"io"
8	"time"
9
10	"bnema.dev/ermite/internal/domain"
11)
12
13// CIArtifactBlock is a staged block of a pending artifact.
14type CIArtifactBlock struct {
15	ArtifactID int64
16	// ID is the uploader's block id (1 to 64 bytes).
17	ID   []byte
18	Size int64
19	// File is the name of the block's file in CIArtifactFiles.
20	File string
21}
22
23// CIArtifactWrite is a change of the artifacts of one repository, written in
24// one atomic batch. The batch requires the usage record of the repository at
25// UsageVersion (0: none stored) and stores Used in it: every write of the
26// artifacts of a repository goes through that record, so two writes never both
27// succeed on the same state, and a write fails with domain.ErrConflict when
28// anything of the repository's artifacts changed since UsageVersion was read.
29//
30// Put stores records: one with Version 0 must not exist yet (the batch then
31// also requires the repository, domain.ErrNotFound once it is deleted), any
32// other must be at its Version. Delete removes records at their Version with
33// their staged blocks. PutBlocks stores blocks (replacing one of the same id),
34// DropBlocks removes all the blocks of the artifacts named.
35type CIArtifactWrite struct {
36	Repo         domain.RepoName
37	Used         int64
38	UsageVersion uint64
39	Put          []domain.CIArtifact
40	Delete       []domain.CIArtifact
41	PutBlocks    []CIArtifactBlock
42	DropBlocks   []int64
43}
44
45// CIArtifactStore keeps the records of the CI artifacts, never their contents.
46// *kvstore.CIArtifacts implements it; the records go with their repository.
47type CIArtifactStore interface {
48	// NextArtifactID takes the next artifact id: global, increasing, never
49	// reused.
50	NextArtifactID(ctx context.Context) (int64, error)
51	// ArtifactUsage returns the bytes charged to the artifacts of the
52	// repository and the version of the record (0, 0 when there is none).
53	ArtifactUsage(ctx context.Context, repo domain.RepoName) (used int64, version uint64, err error)
54	// GetArtifact returns an artifact by id, or domain.ErrNotFound.
55	GetArtifact(ctx context.Context, id int64) (domain.CIArtifact, error)
56	// RunArtifacts returns the artifacts of a run in every state, by id.
57	RunArtifacts(ctx context.Context, repo domain.RepoName, runID int64) ([]domain.CIArtifact, error)
58	// AllArtifacts returns every artifact, for the sweep.
59	AllArtifacts(ctx context.Context) ([]domain.CIArtifact, error)
60	// ArtifactBlocks returns the staged blocks of an artifact.
61	ArtifactBlocks(ctx context.Context, id int64) ([]CIArtifactBlock, error)
62	// BlockArtifactIDs returns the artifacts that have staged blocks, for the
63	// sweep of blocks left by a deleted artifact.
64	BlockArtifactIDs(ctx context.Context) ([]int64, error)
65	// ApplyArtifacts writes w in one batch.
66	ApplyArtifacts(ctx context.Context, w CIArtifactWrite) error
67	// DeleteBlocks removes the staged blocks of an artifact that no longer
68	// exists (left by a repository deleted during an upload).
69	DeleteBlocks(ctx context.Context, id int64) error
70}
71
72// CIArtifactRef names the files of one artifact.
73type CIArtifactRef struct {
74	RunID int64
75	ID    int64
76}
77
78// CIArtifactFiles keeps the contents of the CI artifacts and their staged
79// blocks, never in the metadata store. Files are named by ids only.
80type CIArtifactFiles interface {
81	// PutBlock writes src into a new block file of the artifact, synced, and
82	// returns its size. A failure of src or of the write leaves no file.
83	PutBlock(ctx context.Context, ref CIArtifactRef, file string, src io.Reader) (int64, error)
84	// RemoveBlock deletes one block file; a missing one is not an error.
85	RemoveBlock(ctx context.Context, ref CIArtifactRef, file string) error
86	// Assemble concatenates the block files in order into the content of the
87	// artifact, which replaces any earlier one whole, and returns its size and
88	// digest ("sha256:<hex>"). A missing block file is domain.ErrNotFound.
89	Assemble(ctx context.Context, ref CIArtifactRef, files []string) (size int64, digest string, err error)
90	// Open returns the content from offset, or domain.ErrNotFound.
91	Open(ctx context.Context, ref CIArtifactRef, offset int64) (io.ReadCloser, error)
92	// Remove deletes the content and the blocks of the artifact.
93	Remove(ctx context.Context, ref CIArtifactRef) error
94	// RemoveBlocks deletes the blocks of the artifact.
95	RemoveBlocks(ctx context.Context, ref CIArtifactRef) error
96	// RemoveRuns deletes the files of the runs.
97	RemoveRuns(ctx context.Context, runIDs []int64) error
98	// RunIDs lists the runs that have a directory, ArtifactIDs the artifacts
99	// that have files in one, for the orphan sweep.
100	RunIDs(ctx context.Context) ([]int64, error)
101	ArtifactIDs(ctx context.Context, runID int64) ([]int64, error)
102}
103
104// ArtifactLimits are the settings of the artifacts of the server.
105type ArtifactLimits struct {
106	// Retention is the default and longest retention.
107	Retention time.Duration
108	// Quota is the space of the artifacts of one repository, MaxSize the size
109	// of one artifact.
110	Quota   int64
111	MaxSize int64
112}
113
114// CreatedArtifact is the answer of CreateJobArtifact.
115type CreatedArtifact struct {
116	ID        int64
117	ExpiresAt time.Time
118}
119
120// CreateJobArtifactParams begin an upload.
121type CreateJobArtifactParams struct {
122	JobID     string
123	Name      string
124	MediaType string
125	// ExpiresAt is the expiry asked for; zero for the default.
126	ExpiresAt time.Time
127}
128
129// ArtifactChunk is one message of a download: the artifact in the first one,
130// then data.
131type ArtifactChunk struct {
132	Artifact *domain.CIArtifact
133	Data     []byte
134}
135
136// JobArtifactService is the artifacts side of the runner protocol. The secret
137// is the job token; jobID must be its job (domain.ErrForbidden otherwise), the
138// job must not have ended (a *domain.JobEndedError), and the run is always the
139// job's. *usecase.CI implements it.
140type JobArtifactService interface {
141	CreateJobArtifact(ctx context.Context, secret string, params CreateJobArtifactParams) (CreatedArtifact, error)
142	// UploadJobArtifactBlock stores data as a block of a pending artifact of
143	// the job. An error of data is returned as it is.
144	UploadJobArtifactBlock(ctx context.Context, secret, jobID string, artifactID int64, blockID []byte, data io.Reader) (int64, error)
145	CommitJobArtifact(ctx context.Context, secret, jobID string, artifactID int64, blockIDs [][]byte) (size int64, digest string, err error)
146	FinalizeJobArtifact(ctx context.Context, secret, jobID, name string, size int64, digest string) (domain.CIArtifact, error)
147	ListJobArtifacts(ctx context.Context, secret, jobID, name string, artifactID int64) ([]domain.CIArtifact, error)
148	// DownloadJobArtifact calls send with the artifact, then with the content
149	// from offset in chunks of at most domain.CIArtifactChunk bytes.
150	DownloadJobArtifact(ctx context.Context, secret, jobID string, artifactID, offset int64, send func(ArtifactChunk) error) error
151	DeleteJobArtifact(ctx context.Context, secret, jobID, name string) (int64, error)
152}
153
154// ArtifactList are the artifacts of a run with the space of the repository.
155type ArtifactList struct {
156	Artifacts []domain.CIArtifact
157	Used      int64
158	Quota     int64
159}
160
161// ArtifactService is the owner side of the artifacts. Listing and downloading
162// need a signed-in caller with repo:read, even on a public repository;
163// deleting needs ci:write. *usecase.CI implements it.
164type ArtifactService interface {
165	ListArtifacts(ctx context.Context, p domain.Principal, repo domain.RepoName, runID int64) (ArtifactList, error)
166	// DownloadArtifact is DownloadJobArtifact for an owner.
167	DownloadArtifact(ctx context.Context, p domain.Principal, repo domain.RepoName, artifactID, offset int64, send func(ArtifactChunk) error) error
168	DeleteArtifact(ctx context.Context, p domain.Principal, repo domain.RepoName, artifactID int64) error
169}

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 45

↑↓ moveenter openesc close