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