import Foundation /// One row of `mr list`, and the header half of `mr show`. nonisolated struct MergeRequest: Decodable, Sendable, Hashable, Identifiable { let number: Int64 let title: String let state: String let author: String /// "branch" for a same-repo MR, "owner/name:branch" cross-repo, /// "" when the source is gone. let source: String let targetRef: String let headSHA: String let body: String? let createdAt: Date enum CodingKeys: String, CodingKey { case number, title, state, author, source, body case targetRef = "target_ref" case headSHA = "head_sha" case createdAt = "created_at" } var id: Int64 { number } var isOpen: Bool { state == "open" } } /// The whole of `mr show`. nonisolated struct MRDetail: Decodable, Sendable, Hashable { let number: Int64 let title: String let state: String let author: String let source: String let targetRef: String let headSHA: String let body: String? let milestone: String? let createdAt: Date let checks: [Check]? let checksCombined: String? let unresolvedThreads: Int? let commits: [MRCommit]? let comments: [MRComment]? let reviews: [Review]? enum CodingKeys: String, CodingKey { case number, title, state, author, source, body, milestone, checks, commits, comments, reviews case targetRef = "target_ref" case headSHA = "head_sha" case createdAt = "created_at" case checksCombined = "checks_combined" case unresolvedThreads = "unresolved_threads" } var isOpen: Bool { state == "open" } nonisolated struct Check: Decodable, Sendable, Hashable { let context: String let state: String let url: String? } nonisolated struct MRCommit: Decodable, Sendable, Hashable, Identifiable { let sha: String let subject: String var id: String { sha } var shortSHA: String { String(sha.prefix(10)) } } nonisolated struct MRComment: Decodable, Sendable, Hashable, Identifiable { let author: String let body: String let createdAt: Date enum CodingKeys: String, CodingKey { case author, body case createdAt = "created_at" } var id: String { author + createdAt.timeIntervalSince1970.description + body } } nonisolated struct Review: Decodable, Sendable, Hashable, Identifiable { let reviewer: String let verdict: String /// The review predates the current head — it approved older code. let stale: Bool var id: String { reviewer } } } /// One review thread of `mr threads`. nonisolated struct ReviewThread: Decodable, Sendable, Hashable, Identifiable { let id: Int64 let path: String let side: String // new | old let line: Int64 /// Anchored to an older head; the diff has moved under it. let stale: Bool let resolvedBy: String? let comments: [Comment] enum CodingKeys: String, CodingKey { case id, path, side, line, stale, comments case resolvedBy = "resolved_by" } var isResolved: Bool { resolvedBy != nil } nonisolated struct Comment: Decodable, Sendable, Hashable, Identifiable { let id: Int64 let author: String let body: String let createdAt: Date enum CodingKeys: String, CodingKey { case id, author, body case createdAt = "created_at" } } }