gitbay/Repos/CommitDetailViewModel.swift
64 lines · 1754 bytes
1import Foundation
2import Observation
3
4/// `repo commit` — one commit with its patch, signature verdict and
5/// checks.
6nonisolated struct CommitDetail: Decodable, Sendable, Hashable {
7 let path: String
8 let sha: String
9 let subject: String
10 let message: String?
11 let authorName: String
12 let authorEmail: String
13 let committerEmail: String?
14 let date: Date
15 let signature: Commit.Signature
16 let checks: [Check]?
17 /// The unified patch, parsed client-side exactly like `mr diff`.
18 let diff: String
19
20 enum CodingKeys: String, CodingKey {
21 case path, sha, subject, message, date, signature, checks, diff
22 case authorName = "author_name"
23 case authorEmail = "author_email"
24 case committerEmail = "committer_email"
25 }
26
27 var shortSHA: String { String(sha.prefix(10)) }
28
29 nonisolated struct Check: Decodable, Sendable, Hashable, Identifiable {
30 let context: String
31 let state: String
32 let url: String?
33 var id: String { context }
34 }
35}
36
37@Observable
38@MainActor
39final class CommitDetailViewModel {
40
41 private(set) var state: LoadState<CommitDetail> = .loading
42 private(set) var diff: UnifiedDiff?
43
44 private let client: GitbayClient
45 let repoPath: String
46 let sha: String
47
48 init(client: GitbayClient, repoPath: String, sha: String) {
49 self.client = client
50 self.repoPath = repoPath
51 self.sha = sha
52 }
53
54 func load() async {
55 do {
56 let commit = try await client.read(
57 ["repo", "commit", repoPath, sha], as: CommitDetail.self)
58 diff = UnifiedDiff.parse(commit.diff)
59 state = .loaded(commit)
60 } catch {
61 state = .from(error)
62 }
63 }
64}