1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package ports
4
5import (
6 "time"
7
8 "bnema.dev/ermite/internal/domain"
9)
10
11// The parameters and results of the use case interfaces (services.go). They
12// live here so that the adapters that call the use cases and the use cases
13// themselves share them without importing each other.
14
15// RepoPage is a page of repositories ordered by name.
16type RepoPage struct {
17 Repos []domain.Repo
18 // NextPageToken is empty on the last page.
19 NextPageToken string
20}
21
22// RepoView is a repository with the Git state that belongs in its summary.
23type RepoView struct {
24 domain.Repo // includes ActiveAt, the latest repository activity
25 // DefaultBranch is the branch HEAD points to, even when it does not exist
26 // yet; empty when HEAD is detached or the directory is missing.
27 DefaultBranch string
28}
29
30// CreateRepoParams are the settings of a new repository.
31type CreateRepoParams struct {
32 Name domain.RepoName
33 Description string
34 // Topics are normalized by Create (see domain.NormalizeTopics).
35 Topics []string
36 // Visibility defaults to private when empty.
37 Visibility domain.Visibility
38}
39
40// UpdateRepoParams are the changes of Update; a nil field is left alone.
41type UpdateRepoParams struct {
42 Description *string
43 // Topics replaces the topics; an empty list clears them.
44 Topics *[]string
45 Visibility *domain.Visibility
46 DefaultBranch *string
47 // AllowedMergeModes replaces the allowed merge modes; it must hold at
48 // least one known mode.
49 AllowedMergeModes *[]domain.MergeMode
50 // FailingChecksBlock replaces the setting of that name.
51 FailingChecksBlock *bool
52 // Issues replaces the issues mode.
53 Issues *domain.IssuesMode
54}
55
56// TokenPage is a page of stored tokens, newest first.
57type TokenPage struct {
58 Tokens []domain.Token
59 // NextPageToken is empty on the last page.
60 NextPageToken string
61}
62
63// CreateTokenParams are the settings of a new token.
64type CreateTokenParams struct {
65 Label string
66 // Scopes must not be empty.
67 Scopes []domain.Scope
68 // Repos limits the token to these repositories; empty means every one.
69 Repos []domain.RepoName
70 // BranchPrefixes limits the token to the branches under these prefixes
71 // (see domain.ParseBranchPrefix); empty means every branch.
72 BranchPrefixes []string
73 // ExpiresAt is the zero time for a token that never expires.
74 ExpiresAt time.Time
75}
76
77// CreatedToken is a new token with its secret, which is shown once and never
78// stored.
79type CreatedToken struct {
80 Token domain.Token
81 Secret string
82}
83
84// ListRefsParams selects the refs to list.
85type ListRefsParams struct {
86 // Kinds restricts the result; empty means every kind.
87 Kinds []domain.RefKind
88 // PageSize is 0 for the default, and lowered to MaxRefPageSize.
89 PageSize int
90 // PageToken is the NextPageToken of the previous page, or empty.
91 PageToken string
92}
93
94// RefPage is a page of refs.
95type RefPage struct {
96 Refs []domain.Ref
97 // NextPageToken is empty on the last page.
98 NextPageToken string
99}
100
101// ListCommitsParams selects a page of history.
102type ListCommitsParams struct {
103 // Revision is where the history starts; the zero value is HEAD. Ignored
104 // when PageToken is set: the token pins the commit the first page started
105 // from, so every page walks the same history even if a branch moves.
106 Revision domain.Revision
107 // Path limits the history to the commits that changed it. It must be the
108 // same on every page of a listing.
109 Path domain.TreePath
110 // PageSize is 0 for the default, and lowered to MaxPageSize.
111 PageSize int
112 // PageToken is the NextPageToken of the previous page, or empty.
113 PageToken string
114}
115
116// HistoryPage is a page of history, newest first.
117type HistoryPage struct {
118 Commits []domain.Commit
119 // NextPageToken is empty on the last page.
120 NextPageToken string
121}
122
123// RepoStats are the figures of a repository the home page shows.
124type RepoStats struct {
125 // Commits is the number of commits of the default branch; Recent of them
126 // were committed in the last RecentDays days.
127 Commits, Recent int
128 // LatestTag is the most recently created tag; nil without tags.
129 LatestTag *domain.TagInfo
130 // Activity is the number of commits of each of the last ActivityDays
131 // days, oldest first; the last day ends now. A day is 24 hours.
132 Activity []int
133 // Partial tells that the recent commits were more than MaxCommitTimes:
134 // Recent and Activity count only some of them.
135 Partial bool
136}
137
138// RecentDays is the window of RepoStats.Recent.
139const RecentDays = 30
140
141// ActivityDays is the span of RepoStats.Activity.
142const ActivityDays = 90
143
144// WatchParams select the events of a watch.
145type WatchParams struct {
146 // Topics are TopicHome or "repo:<name>"; empty means TopicHome.
147 Topics []string
148 // ResumeAfter is the id of the last event the caller saw; empty to
149 // receive only new events.
150 ResumeAfter string
151 // Client identifies where the watch comes from, for the limit per client
152 // (MaxWatchersPerClient): an opaque key such as a normalized address; the
153 // web passes its visitor's. Empty only for callers with no client, which
154 // count against MaxWatchers alone.
155 Client string
156 // Ready, when not nil, is called once the topics are valid and the watch
157 // is registered: events published from then on are not missed. Nothing is
158 // sent before it returns.
159 Ready func()
160}
161
162// WatchEvent is one item of a watch.
163type WatchEvent struct {
164 // ID identifies the event, for resuming. Empty on a gap.
165 ID string
166 // Gap tells that events were lost: the caller must reload what it shows.
167 // Event is nil then.
168 Gap bool
169 // Event is a domain.RepoCreated, RepoUpdated, RepoDeleted, PushEvent,
170 // MergeRequestOpened, MergeRequestMerged, MergeRequestClosed,
171 // MergeRequestReady, CommentAdded, RunUpdated or JobUpdated.
172 Event domain.Event
173 // Repo is the state of the repository at delivery, for RepoCreated and
174 // RepoUpdated.
175 Repo *RepoView
176}
177
178// CreateMergeRequestParams describes the merge request to open.
179type CreateMergeRequestParams struct {
180 Title string
181 Description string
182 // Source is required; Target defaults to the default branch.
183 Source, Target string
184}
185
186// ListMergeRequestsParams selects a page of merge requests.
187type ListMergeRequestsParams struct {
188 // State restricts the result; empty means every state.
189 State domain.MRState
190 // PageSize is 0 for the default, and lowered to MaxPageSize.
191 PageSize int
192 // PageToken is the NextPageToken of the previous page, or empty.
193 PageToken string
194}
195
196// MergeRequestPage is a page of merge requests, highest number first.
197type MergeRequestPage struct {
198 MergeRequests []domain.MergeRequest
199 // NextPageToken is empty on the last page.
200 NextPageToken string
201 // Mergeability holds, by number, the mergeability of the open requests of
202 // the page (nil when the server does not compute it).
203 Mergeability map[int64]domain.Mergeability
204}
205
206// ListIssuesParams selects a page of issues from an IssueStore.
207type ListIssuesParams struct {
208 // State restricts the result; empty means every state.
209 State domain.IssueState
210 // PageSize is the most issues returned; 0 or less means no limit. The
211 // use case chooses it.
212 PageSize int
213 // PageToken is the NextPageToken of the previous page, or empty.
214 PageToken string
215}
216
217// IssuePage is a page of issues, highest number first.
218type IssuePage struct {
219 Issues []domain.Issue
220 // NextPageToken is empty on the last page.
221 NextPageToken string
222}
223
224// ListPendingParams selects a page of pending issues.
225type ListPendingParams struct {
226 // PageSize is the page size; the use case applies the default and the
227 // maximum, a store takes it as is (0: every one).
228 PageSize int
229 // PageToken is the NextPageToken of the previous page.
230 PageToken string
231}
232
233// PendingIssuePage is a page of pending issues, oldest first.
234type PendingIssuePage struct {
235 Issues []domain.PendingIssue
236 NextPageToken string
237}
238
239// CreateIssueParams describes the issue to open.
240type CreateIssueParams struct {
241 Title string
242 Body string
243}
244
245// IssueDetail is an issue with its comments.
246type IssueDetail struct {
247 Issue domain.Issue
248 // Comments are oldest first.
249 Comments []domain.IssueComment
250}
251
252// CompareResult describes source commits absent from target, newest first.
253type CompareResult struct {
254 Ahead []domain.Commit
255 Behind bool
256 Exact bool
257}
258
259// PushSummary counts a bounded range; More means additional commits exist.
260type PushSummary struct {
261 Count int
262 More bool
263 Rewritten bool
264}
265
266// MergeRequestDetail is a merge request with its review data.
267type MergeRequestDetail struct {
268 MergeRequest domain.MergeRequest
269 // NewCommits is the unread prefix of Commits; zero if the read head is absent.
270 NewCommits int
271 // HeadUnread reports whether the nonzero head differs from the shared read position.
272 HeadUnread bool
273 // Commits are the commits of the head that the target lacks, newest
274 // first, at most MaxMergeRequestCommits.
275 Commits []domain.Commit
276 CommitsTruncated bool
277 // DiffBaseID is the commit the diff compares from; zero when the source
278 // branch is gone, then the diff is empty.
279 DiffBaseID domain.ObjectID
280 Stats domain.DiffStats
281 Diff domain.Diff
282 // Comments are the comments, oldest first.
283 Comments []domain.Comment
284 // Verdicts are the latest verdict per author in note ID order.
285 Verdicts []domain.AuthorVerdict
286 // Mergeability is zero unless the request is open.
287 Mergeability domain.Mergeability
288 // LastReadID is the head recorded by MarkRead; zero when none.
289 LastReadID domain.ObjectID
290 // LastReadLost tells that since-last-read was asked for, a head was
291 // recorded, but that commit is gone: the diff is against the target.
292 LastReadLost bool
293}
294
295// GetMergeRequestOptions say which diff MergeRequestService.Get reads.
296type GetMergeRequestOptions struct {
297 // SinceLastRead compares the head recorded by MarkRead with the head (see Get).
298 SinceLastRead bool
299 // Files, when set, lists every changed file, without the file-count
300 // limit, and reads the hunks of the files in the window only, each within
301 // the per-file and the total limits of domain.DefaultDiffLimits; generated
302 // files are listed collapsed (domain.OmitGenerated). With Full, the single
303 // file is read without the line limits. Unset, the diff is bounded by
304 // domain.DefaultDiffLimits and generated files are read (the API contract).
305 Files *FileWindow
306 // Base and Head, when not zero, are the diff the caller shows: Get
307 // returns domain.ErrConflict when the request's diff base or head differ
308 // (the branch moved, a read was marked).
309 Base, Head domain.ObjectID
310 // DiffOnly skips the commits of the request (Commits stays empty).
311 DiffOnly bool
312}
313
314// FileWindow is the range [From, To) of files whose hunks are read.
315//
316// Full asks for the one file From read in full: no line limit applies, only
317// the byte guard (domain.OneFileDiffLimits). It requires To == From+1; a
318// window with Full and any other To is domain.ErrInvalid.
319type FileWindow struct {
320 From, To int
321 Full bool
322}
323
324// GetCommitOptions say which diff BrowseService.GetCommit reads.
325type GetCommitOptions struct {
326 // Files, when set, reads the hunks of a window of the files, as
327 // GetMergeRequestOptions.Files does. Unset (the zero value), the diff is
328 // bounded by domain.DefaultDiffLimits.
329 Files *FileWindow
330}
331
332// AddCommentParams describes the comment to add.
333type AddCommentParams struct {
334 // ReplyTo names a non-deleted root; replies cannot specify an anchor or verdict.
335 ReplyTo int64
336 // StartLine starts an inclusive range, requiring a path and 1 <= StartLine < Line.
337 StartLine int
338 // Verdict requires mr:review and is only permitted on roots.
339 Verdict domain.Verdict
340 // Path, Line and Side designate a line of the diff; all empty for a
341 // general comment.
342 Path string
343 Line int
344 Side domain.DiffSide
345 Text string
346}
347
348// MergeParams describes the merge to perform.
349type MergeParams struct {
350 // Mode defaults to fast-forward.
351 Mode domain.MergeMode
352 // HeadID is the commit the caller reviewed; the source branch must still
353 // point to it.
354 HeadID domain.ObjectID
355 // DeleteSource deletes the source branch after the merge.
356 DeleteSource bool
357}
358
359// MergeResult is a merged request and what happened to its source branch.
360type MergeResult struct {
361 domain.MergeRequest
362 // SourceDeleted is true when DeleteSource was asked: the deletion is
363 // requested, and done asynchronously after the merge returned (it is
364 // skipped if the branch moved meanwhile).
365 SourceDeleted bool
366}
367
368// LoginLink is a login link as the owner receives it.
369type LoginLink struct {
370 // URL holds the secret: show it once, never log it.
371 URL string
372 ExpiresAt time.Time
373}
374
375// InboxCounts are the numbers of open items across every repository, whatever
376// the filter.
377type InboxCounts struct{ MergeRequests, Issues, Pending int }
378
379// InboxOverview is what the owner has to look at across every repository: the
380// open merge requests and the open issues, most recently updated first. A
381// section for the items awaiting moderation can be added next to them.
382type InboxOverview struct {
383 Counts InboxCounts
384 // MergeRequests and Issues are those of the filtered repository, or of
385 // every repository when there is no filter. Counts always counts all.
386 MergeRequests []domain.MergeRequest
387 Issues []domain.Issue
388 // Pending are the issues awaiting moderation, in every repository
389 // whatever the filter, oldest first. At most domain.MaxPendingIssues.
390 Pending []domain.PendingIssue
391 // Repos are the repositories that have at least one open item, by name,
392 // whatever the filter: they feed the filter itself.
393 Repos []domain.RepoName
394}
395
396// History query limits.
397const (
398 // MaxMergeRequestCommits bounds the commits returned with a merge request.
399 MaxMergeRequestCommits = 100
400 // MaxCompareCommits bounds a repository comparison.
401 MaxCompareCommits = 500
402 // MaxPushSummaryCommits bounds the commits counted in a push summary.
403 MaxPushSummaryCommits = 100
404)