gitbay/MRs/MRModels.swift
121 lines · 3522 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 createdAt: Date
39 let checks: [Check]?
40 let checksCombined: String?
41 let unresolvedThreads: Int?
42 let commits: [MRCommit]?
43 let comments: [MRComment]?
44 let reviews: [Review]?
45
46 enum CodingKeys: String, CodingKey {
47 case number, title, state, author, source, body, checks, commits, comments, reviews
48 case targetRef = "target_ref"
49 case headSHA = "head_sha"
50 case createdAt = "created_at"
51 case checksCombined = "checks_combined"
52 case unresolvedThreads = "unresolved_threads"
53 }
54
55 var isOpen: Bool { state == "open" }
56
57 nonisolated struct Check: Decodable, Sendable, Hashable {
58 let context: String
59 let state: String
60 let url: String?
61 }
62
63 nonisolated struct MRCommit: Decodable, Sendable, Hashable, Identifiable {
64 let sha: String
65 let subject: String
66 var id: String { sha }
67 var shortSHA: String { String(sha.prefix(10)) }
68 }
69
70 nonisolated struct MRComment: Decodable, Sendable, Hashable, Identifiable {
71 let author: String
72 let body: String
73 let createdAt: Date
74
75 enum CodingKeys: String, CodingKey {
76 case author, body
77 case createdAt = "created_at"
78 }
79
80 var id: String { author + createdAt.timeIntervalSince1970.description + body }
81 }
82
83 nonisolated struct Review: Decodable, Sendable, Hashable, Identifiable {
84 let reviewer: String
85 let verdict: String
86 /// The review predates the current head — it approved older code.
87 let stale: Bool
88 var id: String { reviewer }
89 }
90}
91
92/// One review thread of `mr threads`.
93nonisolated struct ReviewThread: Decodable, Sendable, Hashable, Identifiable {
94 let id: Int64
95 let path: String
96 let side: String // new | old
97 let line: Int64
98 /// Anchored to an older head; the diff has moved under it.
99 let stale: Bool
100 let resolvedBy: String?
101 let comments: [Comment]
102
103 enum CodingKeys: String, CodingKey {
104 case id, path, side, line, stale, comments
105 case resolvedBy = "resolved_by"
106 }
107
108 var isResolved: Bool { resolvedBy != nil }
109
110 nonisolated struct Comment: Decodable, Sendable, Hashable, Identifiable {
111 let id: Int64
112 let author: String
113 let body: String
114 let createdAt: Date
115
116 enum CodingKeys: String, CodingKey {
117 case id, author, body
118 case createdAt = "created_at"
119 }
120 }
121}