1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package ports
4
5import (
6 "bnema.dev/ermite/internal/domain"
7 "context"
8 "io"
9)
10
11// ReleaseWrite atomically changes one repository's metadata. Every write
12// requires UsageVersion (zero requires absence), and each record's Version.
13// Used includes both uploading and uploaded assets.
14type ReleaseWrite struct {
15 Repo domain.RepoName
16 Used int64
17 UsageVersion uint64
18 PutReleases, DeleteReleases []domain.Release
19 PutAssets, DeleteAssets []domain.ReleaseAsset
20}
21
22// ReleaseStore keeps metadata, never contents. *kvstore.Releases implements it.
23type ReleaseStore interface {
24 NextReleaseID(ctx context.Context) (int64, error)
25 ReleaseUsage(ctx context.Context, repo domain.RepoName) (used int64, version uint64, err error)
26 GetRelease(ctx context.Context, repo domain.RepoName, id int64) (domain.Release, error)
27 GetReleaseByTag(ctx context.Context, repo domain.RepoName, tag string) (domain.Release, error)
28 ReleaseRepo(ctx context.Context, id int64) (domain.RepoName, error)
29 ListReleases(ctx context.Context, repo domain.RepoName) ([]domain.Release, error)
30 GetAsset(ctx context.Context, id int64) (domain.ReleaseAsset, error)
31 GetAssetByName(ctx context.Context, repo domain.RepoName, releaseID int64, name string) (domain.ReleaseAsset, error)
32 ListAssets(ctx context.Context, repo domain.RepoName, releaseID int64) ([]domain.ReleaseAsset, error)
33 AllAssets(ctx context.Context) ([]domain.ReleaseAsset, error)
34 ApplyReleases(ctx context.Context, w ReleaseWrite) error
35}
36
37// ReleaseLimits defaults to domain.DefaultReleaseAssetMax (ERMITE_RELEASE_ASSET_MAX),
38// domain.DefaultReleaseAssetsMax (ERMITE_RELEASE_ASSETS_MAX), and
39// domain.DefaultReleaseQuota (ERMITE_RELEASE_QUOTA).
40type ReleaseLimits struct{ AssetMax, AssetsMax, Quota int64 }
41type CreateReleaseParams struct {
42 Tag, TargetCommitish, Title, Notes string
43 Draft, Prerelease, MakeLatest bool
44}
45type UpdateReleaseParams struct {
46 Tag, TargetCommitish, Title, Notes *string
47 Draft, Prerelease, MakeLatest *bool
48}
49
50// ReleaseRef selects exactly one of ID, Tag, Latest.
51type ReleaseRef struct {
52 ID int64
53 Tag string
54 Latest bool
55}
56
57// AssetRef selects ID, (Tag, Name), or (Latest, Name).
58type AssetRef struct {
59 ID int64
60 Tag, Name string
61 Latest bool
62}
63type UploadAssetParams struct {
64 ReleaseID int64
65 Name, Label, ContentType string
66 Size int64
67 Replace bool
68}
69type UpdateAssetParams struct{ Name, Label *string }
70type ReleaseUsage struct {
71 Used int64
72 Limits ReleaseLimits
73}
74type AssetChunk struct {
75 Asset *domain.ReleaseAsset
76 Data []byte
77}
78type ReleasePage struct {
79 Releases []domain.Release
80 NextPageToken string
81}
82
83// ReleaseService manages releases and streams assets; *usecase.Releases implements it.
84type ReleaseService interface {
85 CreateRelease(ctx context.Context, p domain.Principal, repo domain.RepoName, params CreateReleaseParams) (domain.Release, error)
86 GetRelease(ctx context.Context, p domain.Principal, repo domain.RepoName, ref ReleaseRef) (domain.Release, error)
87 ListReleases(ctx context.Context, p domain.Principal, repo domain.RepoName, pageSize int, pageToken string) (ReleasePage, error)
88 UpdateRelease(ctx context.Context, p domain.Principal, repo domain.RepoName, id int64, params UpdateReleaseParams) (domain.Release, error)
89 DeleteRelease(ctx context.Context, p domain.Principal, repo domain.RepoName, id int64) error
90 ListAssets(ctx context.Context, p domain.Principal, repo domain.RepoName, releaseID int64) ([]domain.ReleaseAsset, error)
91 UploadAsset(ctx context.Context, p domain.Principal, repo domain.RepoName, params UploadAssetParams, body io.Reader) (domain.ReleaseAsset, error)
92 UpdateAsset(ctx context.Context, p domain.Principal, repo domain.RepoName, assetID int64, params UpdateAssetParams) (domain.ReleaseAsset, error)
93 DeleteAsset(ctx context.Context, p domain.Principal, repo domain.RepoName, assetID int64) error
94 GetAsset(ctx context.Context, p domain.Principal, repo domain.RepoName, ref AssetRef) (domain.ReleaseAsset, error)
95 // DownloadAsset sends metadata first, then chunks at most domain.CIArtifactChunk;
96 // length less than zero reads to the end.
97 DownloadAsset(ctx context.Context, p domain.Principal, repo domain.RepoName, ref AssetRef, offset, length int64, send func(AssetChunk) error) error
98 Usage(ctx context.Context, p domain.Principal, repo domain.RepoName) (ReleaseUsage, error)
99}
100
101// ReleaseTagWriter creates lightweight tags without moving existing refs.
102// *gitcli.Git implements it. An existing ref returns domain.ErrAlreadyExists.
103type ReleaseTagWriter interface {
104 CreateTag(ctx context.Context, repo domain.RepoName, tag string, target domain.ObjectID) error
105}
106
107// ReleaseTagTrigger handles tag deletion; *usecase.Releases implements it.
108type ReleaseTagTrigger interface {
109 OnRefsMoved(ctx context.Context, repo domain.RepoName, updates []domain.RefUpdate)
110}
111
112// ReleaseSweeper removes stale assets and blobs; *usecase.Releases implements it.
113type ReleaseSweeper interface{ Sweep(ctx context.Context) }
114
115// ReleaseRepoCleaner removes contents after metadata deletion; *usecase.Releases implements it.
116type ReleaseRepoCleaner interface {
117 AssetsOf(ctx context.Context, repo domain.RepoName) ([]domain.ReleaseAsset, error)
118 OnRepoDeleted(ctx context.Context, repo domain.RepoName, assets []domain.ReleaseAsset)
119}