import Foundation import Observation /// `repo commit` — one commit with its patch, signature verdict and /// checks. nonisolated struct CommitDetail: Decodable, Sendable, Hashable { let path: String let sha: String let subject: String let message: String? let authorName: String let authorEmail: String let committerEmail: String? let date: Date let signature: Commit.Signature let checks: [Check]? /// The unified patch, parsed client-side exactly like `mr diff`. let diff: String enum CodingKeys: String, CodingKey { case path, sha, subject, message, date, signature, checks, diff case authorName = "author_name" case authorEmail = "author_email" case committerEmail = "committer_email" } var shortSHA: String { String(sha.prefix(10)) } nonisolated struct Check: Decodable, Sendable, Hashable, Identifiable { let context: String let state: String let url: String? var id: String { context } } } @Observable @MainActor final class CommitDetailViewModel { private(set) var state: LoadState = .loading private(set) var diff: UnifiedDiff? private let client: GitbayClient let repoPath: String let sha: String init(client: GitbayClient, repoPath: String, sha: String) { self.client = client self.repoPath = repoPath self.sha = sha } func load() async { do { let commit = try await client.read( ["repo", "commit", repoPath, sha], as: CommitDetail.self) diff = UnifiedDiff.parse(commit.diff) state = .loaded(commit) } catch { state = .from(error) } } }