gitbay/Builds/BuildModels.swift
62 lines · 1760 bytes
1import Foundation
2import SwiftUI
3
4/// One row of `build list`.
5nonisolated struct Build: Decodable, Sendable, Hashable, Identifiable {
6 let number: Int64
7 let job: String
8 let status: String
9 let sha: String
10 let ref: String
11 let createdAt: Date
12 let finishedAt: Date?
13
14 enum CodingKeys: String, CodingKey {
15 case number, job, status, sha, ref
16 case createdAt = "created_at"
17 case finishedAt = "finished_at"
18 }
19
20 var id: Int64 { number }
21 var shortSHA: String { String(sha.prefix(10)) }
22}
23
24/// `build jobs` — what a trigger can name. A repo with no CI config has
25/// none, which is an empty state rather than an error.
26nonisolated struct CIJob: Decodable, Sendable, Hashable, Identifiable {
27 let name: String
28 let schedule: String?
29 let tags: String?
30
31 var id: String { name }
32
33 /// Why this job runs, in the words the server uses.
34 var trigger: String {
35 if let schedule, !schedule.isEmpty { return "schedule \(schedule)" }
36 if let tags, !tags.isEmpty { return "tags \(tags)" }
37 return "on push"
38 }
39}
40
41extension Build {
42 /// The list row and the detail header must agree on what a status
43 /// looks like; the strings come from the registry.
44 var statusIcon: String {
45 switch status {
46 case "success": "checkmark.circle.fill"
47 case "failure", "error": "xmark.circle.fill"
48 case "running": "circle.dotted"
49 case "queued", "pending": "clock"
50 default: "questionmark.circle"
51 }
52 }
53
54 var statusColor: Color {
55 switch status {
56 case "success": .gbOK
57 case "failure", "error": .gbBad
58 case "running", "queued", "pending": .gbWarn
59 default: .secondary
60 }
61 }
62}