summaryrefslogtreecommitdiff
path: root/Hutch/Models/Builds.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-03-17 23:19:43 -0500
committerChristian Cleberg <[email protected]>2026-03-17 23:19:43 -0500
commit32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5 (patch)
treeee36d421d704e508d5617d803b4c8cbdb4804fe1 /Hutch/Models/Builds.swift
parent8f2057c53e9009c2529c9c4849c914666c0e4b40 (diff)
downloadhutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.gz
hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.tar.bz2
hutch-32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5.zip
v1.0
Diffstat (limited to 'Hutch/Models/Builds.swift')
-rw-r--r--Hutch/Models/Builds.swift111
1 files changed, 111 insertions, 0 deletions
diff --git a/Hutch/Models/Builds.swift b/Hutch/Models/Builds.swift
new file mode 100644
index 0000000..6694c35
--- /dev/null
+++ b/Hutch/Models/Builds.swift
@@ -0,0 +1,111 @@
+import Foundation
+
+// MARK: - Enums
+
+/// Status of a build job.
+enum JobStatus: String, Codable, Sendable {
+ case pending = "PENDING"
+ case queued = "QUEUED"
+ case running = "RUNNING"
+ case success = "SUCCESS"
+ case failed = "FAILED"
+ case cancelled = "CANCELLED"
+ case timeout = "TIMEOUT"
+
+ /// Whether the job can be cancelled.
+ var isCancellable: Bool {
+ switch self {
+ case .pending, .queued, .running: true
+ default: false
+ }
+ }
+}
+
+/// Status of a single build task within a job.
+enum TaskStatus: String, Codable, Sendable {
+ case pending = "PENDING"
+ case running = "RUNNING"
+ case success = "SUCCESS"
+ case failed = "FAILED"
+ case skipped = "SKIPPED"
+}
+
+// MARK: - Build Task
+
+/// A single task within a build job.
+struct BuildTask: Codable, Sendable, Identifiable {
+ var id: String { name }
+ let name: String
+ let status: TaskStatus
+ let log: BuildLog?
+}
+
+// MARK: - Job Summary (for list view)
+
+/// Lightweight job model matching the fields returned by the jobs list query.
+struct JobSummary: Codable, Sendable, Identifiable, Hashable {
+ let id: Int
+ let created: Date
+ let updated: Date
+ let status: JobStatus
+ let note: String?
+ let tags: [String]
+ let visibility: Visibility?
+ let image: String?
+ let tasks: [JobTaskSummary]
+
+ /// Number of completed (success) tasks.
+ var completedTaskCount: Int {
+ tasks.filter { $0.status == .success }.count
+ }
+
+ /// Display label: note if available, otherwise tags joined.
+ var displayLabel: String {
+ if let note, !note.isEmpty {
+ return note
+ }
+ if !tags.isEmpty {
+ return tags.joined(separator: ", ")
+ }
+ return "Job #\(id)"
+ }
+}
+
+/// Minimal task info for the list query.
+struct JobTaskSummary: Codable, Sendable, Hashable {
+ let name: String
+ let status: TaskStatus
+}
+
+// MARK: - Job Detail (for detail view)
+
+/// Full job model with all fields for the detail view.
+struct JobDetail: Codable, Sendable {
+ let id: Int
+ let created: Date
+ let updated: Date
+ let status: JobStatus
+ let note: String?
+ let tags: [String]
+ let visibility: Visibility?
+ let image: String?
+ let manifest: String?
+ let tasks: [BuildTask]
+ let log: BuildLog?
+ let owner: Entity
+}
+
+/// The log associated with a build job.
+struct BuildLog: Codable, Sendable {
+ let fullURL: String
+}
+
+// MARK: - Job Group
+
+/// A group of related build jobs.
+struct JobGroup: Codable, Sendable, Identifiable {
+ let id: Int
+ let created: Date
+ let note: String?
+ let jobs: [JobSummary]
+}