gitbay/MRs/MRModels.swift
122 lines · 3560 bytes
1import Foundation
2
3/// One row of `mr list`, and the header half of `mr show`.
4nonisolated struct MergeRequest: Decodable, Sendable, Hashable, Identifiable {
5 let number: Int64
6 let title: String
7 let state: String
8 let author: String
9 /// "branch" for a same-repo MR, "owner/name:branch" cross-repo,
10 /// "" when the source is gone.
11 let source: String
12 let targetRef: String
13 let headSHA: String
14 let body: String?
15 let createdAt: Date
16
17 enum CodingKeys: String, CodingKey {
18 case number, title, state, author, source, body
19 case targetRef = "target_ref"
20 case headSHA = "head_sha"
21 case createdAt = "created_at"
22 }
23
24 var id: Int64 { number }
25 var isOpen: Bool { state == "open" }
26}
27
28/// The whole of `mr show`.
29nonisolated struct MRDetail: Decodable, Sendable, Hashable {
30 let number: Int64
31 let title: String
32 let state: String
33 let author: String
34 let source: String
35 let targetRef: String
36 let headSHA: String
37 let body: String?
38 let milestone: String?
39 let createdAt: Date
40 let checks: [Check]?
41 let checksCombined: String?
42 let unresolvedThreads: Int?
43 let commits: [MRCommit]?
44 let comments: [MRComment]?
45 let reviews: [Review]?
46
47 enum CodingKeys: String, CodingKey {
48 case number, title, state, author, source, body, milestone, checks, commits, comments, reviews
49 case targetRef = "target_ref"
50 case headSHA = "head_sha"
51 case createdAt = "created_at"
52 case checksCombined = "checks_combined"
53 case unresolvedThreads = "unresolved_threads"
54 }
55
56 var isOpen: Bool { state == "open" }
57
58 nonisolated struct Check: Decodable, Sendable, Hashable {
59 let context: String
60 let state: String
61 let url: String?
62 }
63
64 nonisolated struct MRCommit: Decodable, Sendable, Hashable, Identifiable {
65 let sha: String
66 let subject: String
67 var id: String { sha }
68 var shortSHA: String { String(sha.prefix(10)) }
69 }
70
71 nonisolated struct MRComment: Decodable, Sendable, Hashable, Identifiable {
72 let author: String
73 let body: String
74 let createdAt: Date
75
76 enum CodingKeys: String, CodingKey {
77 case author, body
78 case createdAt = "created_at"
79 }
80
81 var id: String { author + createdAt.timeIntervalSince1970.description + body }
82 }
83
84 nonisolated struct Review: Decodable, Sendable, Hashable, Identifiable {
85 let reviewer: String
86 let verdict: String
87 /// The review predates the current head — it approved older code.
88 let stale: Bool
89 var id: String { reviewer }
90 }
91}
92
93/// One review thread of `mr threads`.
94nonisolated struct ReviewThread: Decodable, Sendable, Hashable, Identifiable {
95 let id: Int64
96 let path: String
97 let side: String // new | old
98 let line: Int64
99 /// Anchored to an older head; the diff has moved under it.
100 let stale: Bool
101 let resolvedBy: String?
102 let comments: [Comment]
103
104 enum CodingKeys: String, CodingKey {
105 case id, path, side, line, stale, comments
106 case resolvedBy = "resolved_by"
107 }
108
109 var isResolved: Bool { resolvedBy != nil }
110
111 nonisolated struct Comment: Decodable, Sendable, Hashable, Identifiable {
112 let id: Int64
113 let author: String
114 let body: String
115 let createdAt: Date
116
117 enum CodingKeys: String, CodingKey {
118 case id, author, body
119 case createdAt = "created_at"
120 }
121 }
122}