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