Commit b0ba9d0cc4

b0ba9d0cc4bb20317996cf6e577cd3821470e668

parent: 303f741e56

Unsigned

cmc <hello@cleberg.net> · 2026-04-14 01:07 UTC

fix: sonarqube code smell fixes

Layout: unified · split

Hutch.xcodeproj/project.pbxproj +8 −8
@@ -515,7 +515,7 @@
515 ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 515 ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
516 CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; 516 CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
517 CODE_SIGN_STYLE = Automatic; 517 CODE_SIGN_STYLE = Automatic;
518 CURRENT_PROJECT_VERSION = 71; 518 CURRENT_PROJECT_VERSION = 72;
519 DEVELOPMENT_TEAM = ZCNAX3VL9D; 519 DEVELOPMENT_TEAM = ZCNAX3VL9D;
520 ENABLE_PREVIEWS = YES; 520 ENABLE_PREVIEWS = YES;
521 GENERATE_INFOPLIST_FILE = YES; 521 GENERATE_INFOPLIST_FILE = YES;
@@ -532,7 +532,7 @@
532 "$(inherited)", 532 "$(inherited)",
533 "@executable_path/Frameworks", 533 "@executable_path/Frameworks",
534 ); 534 );
535 MARKETING_VERSION = 3.1.3; 535 MARKETING_VERSION = 3.1.4;
536 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; 536 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
537 PRODUCT_NAME = "$(TARGET_NAME)"; 537 PRODUCT_NAME = "$(TARGET_NAME)";
538 STRING_CATALOG_GENERATE_SYMBOLS = YES; 538 STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -552,7 +552,7 @@
552 ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 552 ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
553 CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; 553 CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
554 CODE_SIGN_STYLE = Automatic; 554 CODE_SIGN_STYLE = Automatic;
555 CURRENT_PROJECT_VERSION = 71; 555 CURRENT_PROJECT_VERSION = 72;
556 DEVELOPMENT_TEAM = ZCNAX3VL9D; 556 DEVELOPMENT_TEAM = ZCNAX3VL9D;
557 ENABLE_PREVIEWS = YES; 557 ENABLE_PREVIEWS = YES;
558 GENERATE_INFOPLIST_FILE = YES; 558 GENERATE_INFOPLIST_FILE = YES;
@@ -569,7 +569,7 @@
569 "$(inherited)", 569 "$(inherited)",
570 "@executable_path/Frameworks", 570 "@executable_path/Frameworks",
571 ); 571 );
572 MARKETING_VERSION = 3.1.3; 572 MARKETING_VERSION = 3.1.4;
573 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; 573 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
574 PRODUCT_NAME = "$(TARGET_NAME)"; 574 PRODUCT_NAME = "$(TARGET_NAME)";
575 STRING_CATALOG_GENERATE_SYMBOLS = YES; 575 STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -632,7 +632,7 @@
632 APPLICATION_EXTENSION_API_ONLY = YES; 632 APPLICATION_EXTENSION_API_ONLY = YES;
633 CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; 633 CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
634 CODE_SIGN_STYLE = Automatic; 634 CODE_SIGN_STYLE = Automatic;
635 CURRENT_PROJECT_VERSION = 71; 635 CURRENT_PROJECT_VERSION = 72;
636 DEVELOPMENT_TEAM = ZCNAX3VL9D; 636 DEVELOPMENT_TEAM = ZCNAX3VL9D;
637 GENERATE_INFOPLIST_FILE = NO; 637 GENERATE_INFOPLIST_FILE = NO;
638 INFOPLIST_FILE = HutchWidgetExtension/Info.plist; 638 INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -642,7 +642,7 @@
642 "@executable_path/Frameworks", 642 "@executable_path/Frameworks",
643 "@executable_path/../../Frameworks", 643 "@executable_path/../../Frameworks",
644 ); 644 );
645 MARKETING_VERSION = 3.1.3; 645 MARKETING_VERSION = 3.1.4;
646 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; 646 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
647 PRODUCT_NAME = "$(TARGET_NAME)"; 647 PRODUCT_NAME = "$(TARGET_NAME)";
648 SKIP_INSTALL = YES; 648 SKIP_INSTALL = YES;
@@ -661,7 +661,7 @@
661 APPLICATION_EXTENSION_API_ONLY = YES; 661 APPLICATION_EXTENSION_API_ONLY = YES;
662 CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; 662 CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
663 CODE_SIGN_STYLE = Automatic; 663 CODE_SIGN_STYLE = Automatic;
664 CURRENT_PROJECT_VERSION = 71; 664 CURRENT_PROJECT_VERSION = 72;
665 DEVELOPMENT_TEAM = ZCNAX3VL9D; 665 DEVELOPMENT_TEAM = ZCNAX3VL9D;
666 GENERATE_INFOPLIST_FILE = NO; 666 GENERATE_INFOPLIST_FILE = NO;
667 INFOPLIST_FILE = HutchWidgetExtension/Info.plist; 667 INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -671,7 +671,7 @@
671 "@executable_path/Frameworks", 671 "@executable_path/Frameworks",
672 "@executable_path/../../Frameworks", 672 "@executable_path/../../Frameworks",
673 ); 673 );
674 MARKETING_VERSION = 3.1.3; 674 MARKETING_VERSION = 3.1.4;
675 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; 675 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
676 PRODUCT_NAME = "$(TARGET_NAME)"; 676 PRODUCT_NAME = "$(TARGET_NAME)";
677 SKIP_INSTALL = YES; 677 SKIP_INSTALL = YES;
Hutch/Models/Git.swift +2 −2
@@ -4,9 +4,9 @@ import Foundation
4 4
5/// Repository visibility level. 5/// Repository visibility level.
6enum Visibility: String, Codable, Sendable { 6enum Visibility: String, Codable, Sendable {
7 case `public` = "PUBLIC" 7 case publicVisibility = "PUBLIC"
8 case unlisted = "UNLISTED" 8 case unlisted = "UNLISTED"
9 case `private` = "PRIVATE" 9 case privateVisibility = "PRIVATE"
10} 10}
11 11
12/// Repository access mode. 12/// Repository access mode.
Hutch/Models/Project.swift +2 −2
@@ -230,11 +230,11 @@ extension String {
230extension Visibility { 230extension Visibility {
231 var displayName: String { 231 var displayName: String {
232 switch self { 232 switch self {
233 case .public: 233 case .publicVisibility:
234 "Public" 234 "Public"
235 case .unlisted: 235 case .unlisted:
236 "Unlisted" 236 "Unlisted"
237 case .private: 237 case .privateVisibility:
238 "Private" 238 "Private"
239 } 239 }
240 } 240 }
Hutch/Models/RepositorySummary.swift +34 −29
@@ -20,26 +20,29 @@ struct RepositorySummary: Codable, Sendable, Identifiable, Hashable {
20 case head = "HEAD" 20 case head = "HEAD"
21 } 21 }
22 22
23 init( 23 /// Grouped initializer fields (single parameter keeps APIs explicit without exceeding parameter-count limits).
24 id: Int, 24 struct Fields: Sendable, Hashable {
25 rid: String, 25 let id: Int
26 service: SRHTService, 26 let rid: String
27 name: String, 27 let service: SRHTService
28 description: String?, 28 let name: String
29 visibility: Visibility, 29 let description: String?
30 updated: Date, 30 let visibility: Visibility
31 owner: Entity, 31 let updated: Date
32 head: Reference? 32 let owner: Entity
33 ) { 33 let head: Reference?
34 self.id = id 34 }
35 self.rid = rid 35
36 self.service = service 36 init(fields: Fields) {
37 self.name = name 37 id = fields.id
38 self.description = description 38 rid = fields.rid
39 self.visibility = visibility 39 service = fields.service
40 self.updated = updated 40 name = fields.name
41 self.owner = owner 41 description = fields.description
42 self.head = head 42 visibility = fields.visibility
43 updated = fields.updated
44 owner = fields.owner
45 head = fields.head
43 } 46 }
44 47
45 init(from decoder: any Decoder) throws { 48 init(from decoder: any Decoder) throws {
@@ -69,15 +72,17 @@ extension RepositorySummary {
69 head: Reference? = nil 72 head: Reference? = nil
70 ) -> RepositorySummary { 73 ) -> RepositorySummary {
71 RepositorySummary( 74 RepositorySummary(
72 id: id, 75 fields: .init(
73 rid: rid, 76 id: id,
74 service: service, 77 rid: rid,
75 name: name ?? self.name, 78 service: service,
76 description: description ?? self.description, 79 name: name ?? self.name,
77 visibility: visibility ?? self.visibility, 80 description: description ?? self.description,
78 updated: updated ?? self.updated, 81 visibility: visibility ?? self.visibility,
79 owner: owner, 82 updated: updated ?? self.updated,
80 head: head ?? self.head 83 owner: owner,
84 head: head ?? self.head
85 )
81 ) 86 )
82 } 87 }
83 88
Hutch/Networking/ProjectService.swift +5 −5
@@ -49,7 +49,7 @@ private struct ProjectSummaryPayload: Decodable, Sendable {
49 name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 49 name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
50 description = try container.decodeIfPresent(String.self, forKey: .description) 50 description = try container.decodeIfPresent(String.self, forKey: .description)
51 website = try container.decodeIfPresent(String.self, forKey: .website) 51 website = try container.decodeIfPresent(String.self, forKey: .website)
52 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public 52 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
53 tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? [] 53 tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? []
54 updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast 54 updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast
55 } 55 }
@@ -90,7 +90,7 @@ private struct ProjectDetailPayload: Decodable, Sendable {
90 name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 90 name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
91 description = try container.decodeIfPresent(String.self, forKey: .description) 91 description = try container.decodeIfPresent(String.self, forKey: .description)
92 website = try container.decodeIfPresent(String.self, forKey: .website) 92 website = try container.decodeIfPresent(String.self, forKey: .website)
93 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public 93 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
94 tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? [] 94 tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? []
95 updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast 95 updated = try container.decodeIfPresent(Date.self, forKey: .updated) ?? .distantPast
96 mailingLists = try container.decodeIfPresent(ProjectMailingListPage.self, forKey: .mailingLists) ?? .empty 96 mailingLists = try container.decodeIfPresent(ProjectMailingListPage.self, forKey: .mailingLists) ?? .empty
@@ -126,7 +126,7 @@ private struct ProjectMailingListPayload: Decodable, Sendable {
126 rid = try container.decode(String.self, forKey: .rid) 126 rid = try container.decode(String.self, forKey: .rid)
127 name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 127 name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
128 description = try container.decodeIfPresent(String.self, forKey: .description) 128 description = try container.decodeIfPresent(String.self, forKey: .description)
129 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public 129 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
130 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") 130 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
131 } 131 }
132} 132}
@@ -160,7 +160,7 @@ private struct ProjectSourcePayload: Decodable, Sendable {
160 rid = try container.decode(String.self, forKey: .rid) 160 rid = try container.decode(String.self, forKey: .rid)
161 name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 161 name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
162 description = try container.decodeIfPresent(String.self, forKey: .description) 162 description = try container.decodeIfPresent(String.self, forKey: .description)
163 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public 163 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
164 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") 164 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
165 repoType = try container.decodeIfPresent(Project.SourceRepo.RepoType.self, forKey: .repoType) ?? .git 165 repoType = try container.decodeIfPresent(Project.SourceRepo.RepoType.self, forKey: .repoType) ?? .git
166 } 166 }
@@ -193,7 +193,7 @@ private struct ProjectTrackerPayload: Decodable, Sendable {
193 rid = try container.decode(String.self, forKey: .rid) 193 rid = try container.decode(String.self, forKey: .rid)
194 name = try container.decodeIfPresent(String.self, forKey: .name) ?? "" 194 name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
195 description = try container.decodeIfPresent(String.self, forKey: .description) 195 description = try container.decodeIfPresent(String.self, forKey: .description)
196 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .public 196 visibility = try container.decodeIfPresent(Visibility.self, forKey: .visibility) ?? .publicVisibility
197 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown") 197 owner = try container.decodeIfPresent(Entity.self, forKey: .owner) ?? Entity(canonicalName: "~unknown")
198 } 198 }
199} 199}
Hutch/Networking/SRHTClient.swift +19 −29
@@ -57,7 +57,7 @@ final class SRHTClient: Sendable {
57 service: SRHTService, 57 service: SRHTService,
58 query: String, 58 query: String,
59 variables: [String: any Sendable]? = nil, 59 variables: [String: any Sendable]? = nil,
60 responseType: T.Type 60 responseType _: T.Type
61 ) async throws -> T { 61 ) async throws -> T {
62 guard let token = _token.withLock({ $0 }), !token.isEmpty else { 62 guard let token = _token.withLock({ $0 }), !token.isEmpty else {
63 throw SRHTError.unauthorized 63 throw SRHTError.unauthorized
@@ -164,20 +164,14 @@ final class SRHTClient: Sendable {
164 /// - service: The target SourceHut service. 164 /// - service: The target SourceHut service.
165 /// - query: The GraphQL mutation string. 165 /// - query: The GraphQL mutation string.
166 /// - variables: Variables dict; the file variable should be set to `nil`. 166 /// - variables: Variables dict; the file variable should be set to `nil`.
167 /// - fileVariablePath: The dot-separated path to the file variable (e.g. "input.avatar"). 167 /// - file: Multipart file payload (`variablePath` is the dot-separated GraphQL variable, e.g. `input.avatar`).
168 /// - fileData: The raw file data (e.g. JPEG).
169 /// - fileName: The file name to send (e.g. "avatar.jpg").
170 /// - mimeType: The MIME type (e.g. "image/jpeg").
171 /// - responseType: The expected `Decodable` type nested under `data`. 168 /// - responseType: The expected `Decodable` type nested under `data`.
172 func executeMultipart<T: Decodable>( 169 func executeMultipart<T: Decodable>(
173 service: SRHTService, 170 service: SRHTService,
174 query: String, 171 query: String,
175 variables: [String: any Sendable], 172 variables: [String: any Sendable],
176 fileVariablePath: String, 173 file: MultipartUploadFile,
177 fileData: Data, 174 responseType _: T.Type
178 fileName: String,
179 mimeType: String,
180 responseType: T.Type
181 ) async throws -> T { 175 ) async throws -> T {
182 guard let token = _token.withLock({ $0 }), !token.isEmpty else { 176 guard let token = _token.withLock({ $0 }), !token.isEmpty else {
183 throw SRHTError.unauthorized 177 throw SRHTError.unauthorized
@@ -197,8 +191,8 @@ final class SRHTClient: Sendable {
197 ) 191 )
198 let operationsData = try encoder.encode(operationsBody) 192 let operationsData = try encoder.encode(operationsBody)
199 193
200 // Build the map JSON: { "0": ["variables.<fileVariablePath>"] } 194 // Build the map JSON: { "0": ["variables.<variablePath>"] }
201 let mapDict = ["0": ["variables.\(fileVariablePath)"]] 195 let mapDict = ["0": ["variables.\(file.variablePath)"]]
202 let mapData = try encoder.encode(mapDict) 196 let mapData = try encoder.encode(mapDict)
203 197
204 // Assemble multipart body 198 // Assemble multipart body
@@ -220,9 +214,9 @@ final class SRHTClient: Sendable {
220 214
221 // Part: file 215 // Part: file
222 body.append("--\(boundary)\r\n") 216 body.append("--\(boundary)\r\n")
223 body.append("Content-Disposition: form-data; name=\"0\"; filename=\"\(fileName)\"\r\n") 217 body.append("Content-Disposition: form-data; name=\"0\"; filename=\"\(file.fileName)\"\r\n")
224 body.append("Content-Type: \(mimeType)\r\n\r\n") 218 body.append("Content-Type: \(file.mimeType)\r\n\r\n")
225 body.append(fileData) 219 body.append(file.fileData)
226 body.append("\r\n") 220 body.append("\r\n")
227 221
228 // Closing boundary 222 // Closing boundary
@@ -311,7 +305,7 @@ final class SRHTClient: Sendable {
311 query: String, 305 query: String,
312 variables: [String: any Sendable], 306 variables: [String: any Sendable],
313 files: [MultipartUploadFile], 307 files: [MultipartUploadFile],
314 responseType: T.Type 308 responseType _: T.Type
315 ) async throws -> T { 309 ) async throws -> T {
316 guard let token = _token.withLock({ $0 }), !token.isEmpty else { 310 guard let token = _token.withLock({ $0 }), !token.isEmpty else {
317 throw SRHTError.unauthorized 311 throw SRHTError.unauthorized
@@ -408,15 +402,14 @@ final class SRHTClient: Sendable {
408 service: SRHTService, 402 service: SRHTService,
409 query: String, 403 query: String,
410 variables: [String: any Sendable]? = nil, 404 variables: [String: any Sendable]? = nil,
411 responseType: T.Type, 405 responseType _: T.Type,
412 cacheKey: String 406 cacheKey: String
413 ) async throws -> T { 407 ) async throws -> T {
414 // Try cache first 408 // Try cache first
415 if let cachedData = responseCache.get(forKey: cacheKey) { 409 if let cachedData = responseCache.get(forKey: cacheKey),
416 if let cached = try? decoder.decode(GraphQLResponse<T>.self, from: cachedData), 410 let cached = try? decoder.decode(GraphQLResponse<T>.self, from: cachedData),
417 let data = cached.data { 411 let data = cached.data {
418 return data 412 return data
419 }
420 } 413 }
421 414
422 // No cache hit — fetch normally 415 // No cache hit — fetch normally
@@ -434,7 +427,7 @@ final class SRHTClient: Sendable {
434 service: SRHTService, 427 service: SRHTService,
435 query: String, 428 query: String,
436 variables: [String: any Sendable]? = nil, 429 variables: [String: any Sendable]? = nil,
437 responseType: T.Type, 430 responseType _: T.Type,
438 cacheKey: String 431 cacheKey: String
439 ) async throws -> T { 432 ) async throws -> T {
440 guard let token = _token.withLock({ $0 }), !token.isEmpty else { 433 guard let token = _token.withLock({ $0 }), !token.isEmpty else {
@@ -580,8 +573,7 @@ final class SRHTClient: Sendable {
580 service: SRHTService, 573 service: SRHTService,
581 query: String, 574 query: String,
582 variables: [String: any Sendable]? = nil, 575 variables: [String: any Sendable]? = nil,
583 resultKeyPath: String, 576 resultKeyPath: String
584 type: T.Type
585 ) -> SRHTPaginatedSequence<T> { 577 ) -> SRHTPaginatedSequence<T> {
586 SRHTPaginatedSequence( 578 SRHTPaginatedSequence(
587 client: self, 579 client: self,
@@ -598,16 +590,14 @@ final class SRHTClient: Sendable {
598 service: SRHTService, 590 service: SRHTService,
599 query: String, 591 query: String,
600 variables: [String: any Sendable]? = nil, 592 variables: [String: any Sendable]? = nil,
601 resultKeyPath: String, 593 resultKeyPath: String
602 type: T.Type
603 ) async throws -> [T] { 594 ) async throws -> [T] {
604 var all: [T] = [] 595 var all: [T] = []
605 for try await element in paginated( 596 for try await element in paginated(
606 service: service, 597 service: service,
607 query: query, 598 query: query,
608 variables: variables, 599 variables: variables,
609 resultKeyPath: resultKeyPath, 600 resultKeyPath: resultKeyPath
610 type: type
611 ) { 601 ) {
612 all.append(element) 602 all.append(element)
613 } 603 }
Hutch/Views/Builds/BuildDetailView.swift +3 −3
@@ -468,7 +468,7 @@ private struct EditResubmitBuildSheet: View {
468 _manifest = State(initialValue: job.manifest ?? "") 468 _manifest = State(initialValue: job.manifest ?? "")
469 _tagsText = State(initialValue: job.tags.joined(separator: ", ")) 469 _tagsText = State(initialValue: job.tags.joined(separator: ", "))
470 _note = State(initialValue: job.note ?? "") 470 _note = State(initialValue: job.note ?? "")
471 _visibility = State(initialValue: job.visibility ?? .public) 471 _visibility = State(initialValue: job.visibility ?? .publicVisibility)
472 } 472 }
473 473
474 var body: some View { 474 var body: some View {
@@ -491,9 +491,9 @@ private struct EditResubmitBuildSheet: View {
491 .autocorrectionDisabled() 491 .autocorrectionDisabled()
492 .themedRow() 492 .themedRow()
493 Picker("Visibility", selection: $visibility) { 493 Picker("Visibility", selection: $visibility) {
494 Text("Public").tag(Visibility.public) 494 Text("Public").tag(Visibility.publicVisibility)
495 Text("Unlisted").tag(Visibility.unlisted) 495 Text("Unlisted").tag(Visibility.unlisted)
496 Text("Private").tag(Visibility.private) 496 Text("Private").tag(Visibility.privateVisibility)
497 } 497 }
498 .themedRow() 498 .themedRow()
499 Toggle("Start build now", isOn: $execute) 499 Toggle("Start build now", isOn: $execute)
Hutch/Views/Builds/BuildListView.swift +3 −3
@@ -265,7 +265,7 @@ private struct SubmitBuildSheet: View {
265 @State private var note = "" 265 @State private var note = ""
266 @State private var secrets = false 266 @State private var secrets = false
267 @State private var execute = true 267 @State private var execute = true
268 @State private var visibility: Visibility = .public 268 @State private var visibility: Visibility = .publicVisibility
269 269
270 init(viewModel: BuildListViewModel, onSubmitted: @escaping (Int) -> Void) { 270 init(viewModel: BuildListViewModel, onSubmitted: @escaping (Int) -> Void) {
271 self.viewModel = viewModel 271 self.viewModel = viewModel
@@ -293,9 +293,9 @@ private struct SubmitBuildSheet: View {
293 .autocorrectionDisabled() 293 .autocorrectionDisabled()
294 .themedRow() 294 .themedRow()
295 Picker("Visibility", selection: $visibility) { 295 Picker("Visibility", selection: $visibility) {
296 Text("Public").tag(Visibility.public) 296 Text("Public").tag(Visibility.publicVisibility)
297 Text("Unlisted").tag(Visibility.unlisted) 297 Text("Unlisted").tag(Visibility.unlisted)
298 Text("Private").tag(Visibility.private) 298 Text("Private").tag(Visibility.privateVisibility)
299 } 299 }
300 .themedRow() 300 .themedRow()
301 Toggle("Start build now", isOn: $execute) 301 Toggle("Start build now", isOn: $execute)
Hutch/Views/Lookup/LookupView.swift +11 −9
@@ -233,15 +233,17 @@ final class LookupViewModel {
233 233
234 let repository = try await appState.resolveRepository(owner: owner, name: name, service: service) 234 let repository = try await appState.resolveRepository(owner: owner, name: name, service: service)
235 let resolvedRepository = RepositorySummary( 235 let resolvedRepository = RepositorySummary(
236 id: repository.id, 236 fields: .init(
237 rid: repository.rid, 237 id: repository.id,
238 service: service, 238 rid: repository.rid,
239 name: repository.name, 239 service: service,
240 description: repository.description, 240 name: repository.name,
241 visibility: repository.visibility, 241 description: repository.description,
242 updated: repository.updated, 242 visibility: repository.visibility,
243 owner: repository.owner, 243 updated: repository.updated,
244 head: repository.head 244 owner: repository.owner,
245 head: repository.head
246 )
245 ) 247 )
246 248
247 return .repository(resolvedRepository) 249 return .repository(resolvedRepository)
Hutch/Views/Lookup/UserProfileViewModel.swift +11 −9
@@ -179,15 +179,17 @@ final class UserProfileViewModel {
179 179
180 func repositorySummary(service: SRHTService) -> RepositorySummary { 180 func repositorySummary(service: SRHTService) -> RepositorySummary {
181 RepositorySummary( 181 RepositorySummary(
182 id: id, 182 fields: .init(
183 rid: rid, 183 id: id,
184 service: service, 184 rid: rid,
185 name: name, 185 service: service,
186 description: description, 186 name: name,
187 visibility: visibility, 187 description: description,
188 updated: updated, 188 visibility: visibility,
189 owner: owner, 189 updated: updated,
190 head: head 190 owner: owner,
191 head: head
192 )
191 ) 193 )
192 } 194 }
193 } 195 }
Hutch/Views/Pastes/PasteDetailView.swift +5 −5
@@ -442,27 +442,27 @@ private struct PasteVisibilitySheet: View {
442 } 442 }
443 443
444 private var visibilityOptions: [Visibility] { 444 private var visibilityOptions: [Visibility] {
445 [.public, .unlisted, .private] 445 [.publicVisibility, .unlisted, .privateVisibility]
446 } 446 }
447 447
448 private func title(for visibility: Visibility) -> String { 448 private func title(for visibility: Visibility) -> String {
449 switch visibility { 449 switch visibility {
450 case .public: 450 case .publicVisibility:
451 "Public" 451 "Public"
452 case .unlisted: 452 case .unlisted:
453 "Unlisted" 453 "Unlisted"
454 case .private: 454 case .privateVisibility:
455 "Private" 455 "Private"
456 } 456 }
457 } 457 }
458 458
459 private func description(for visibility: Visibility) -> String { 459 private func description(for visibility: Visibility) -> String {
460 switch visibility { 460 switch visibility {
461 case .public: 461 case .publicVisibility:
462 "Visible to everyone and listed on your profile." 462 "Visible to everyone and listed on your profile."
463 case .unlisted: 463 case .unlisted:
464 "Visible to anyone with the URL, but not listed on your profile." 464 "Visible to anyone with the URL, but not listed on your profile."
465 case .private: 465 case .privateVisibility:
466 "Visible only to explicitly allowed viewers." 466 "Visible only to explicitly allowed viewers."
467 } 467 }
468 } 468 }
Hutch/Views/Pastes/PasteListView.swift +8 −8
@@ -179,33 +179,33 @@ struct PasteListView: View {
179 179
180 private func nextVisibilityLabel(for visibility: Visibility) -> String { 180 private func nextVisibilityLabel(for visibility: Visibility) -> String {
181 switch visibility { 181 switch visibility {
182 case .public: 182 case .publicVisibility:
183 return "Make Unlisted" 183 return "Make Unlisted"
184 case .unlisted: 184 case .unlisted:
185 return "Make Private" 185 return "Make Private"
186 case .private: 186 case .privateVisibility:
187 return "Make Public" 187 return "Make Public"
188 } 188 }
189 } 189 }
190 190
191 private func nextVisibilityIcon(for visibility: Visibility) -> String { 191 private func nextVisibilityIcon(for visibility: Visibility) -> String {
192 switch visibility { 192 switch visibility {
193 case .public: 193 case .publicVisibility:
194 return "eye.slash" 194 return "eye.slash"
195 case .unlisted: 195 case .unlisted:
196 return "lock" 196 return "lock"
197 case .private: 197 case .privateVisibility:
198 return "globe" 198 return "globe"
199 } 199 }
200 } 200 }
201 201
202 private func nextVisibilityColor(for visibility: Visibility) -> Color { 202 private func nextVisibilityColor(for visibility: Visibility) -> Color {
203 switch visibility { 203 switch visibility {
204 case .public: 204 case .publicVisibility:
205 return .orange 205 return .orange
206 case .unlisted: 206 case .unlisted:
207 return .red 207 return .red
208 case .private: 208 case .privateVisibility:
209 return .green 209 return .green
210 } 210 }
211 } 211 }
@@ -316,9 +316,9 @@ private struct CreatePasteSheet: View {
316 316
317 Section("Visibility") { 317 Section("Visibility") {
318 Picker("Visibility", selection: $visibility) { 318 Picker("Visibility", selection: $visibility) {
319 Text("Public").tag(Visibility.public) 319 Text("Public").tag(Visibility.publicVisibility)
320 Text("Unlisted").tag(Visibility.unlisted) 320 Text("Unlisted").tag(Visibility.unlisted)
321 Text("Private").tag(Visibility.private) 321 Text("Private").tag(Visibility.privateVisibility)
322 } 322 }
323 .themedRow() 323 .themedRow()
324 } 324 }
Hutch/Views/Pastes/PasteListViewModel.swift +4 −4
@@ -131,12 +131,12 @@ final class PasteListViewModel {
131 func cycleVisibility(for paste: Paste) async { 131 func cycleVisibility(for paste: Paste) async {
132 let next: Visibility 132 let next: Visibility
133 switch paste.visibility { 133 switch paste.visibility {
134 case .public: 134 case .publicVisibility:
135 next = .unlisted 135 next = .unlisted
136 case .unlisted: 136 case .unlisted:
137 next = .private 137 next = .privateVisibility
138 case .private: 138 case .privateVisibility:
139 next = .public 139 next = .publicVisibility
140 } 140 }
141 141
142 let original = pastes 142 let original = pastes
Hutch/Views/Repositories/FileTreeViewModel.swift +1 −4
@@ -327,14 +327,11 @@ final class FileTreeViewModel {
327 } 327 }
328 328
329 case .binaryBlob(let blob): 329 case .binaryBlob(let blob):
330 if blob.content != nil { 330 if blob.content != nil || blob.id == nil {
331 viewingEntry = entry 331 viewingEntry = entry
332 viewingObject = object 332 viewingObject = object
333 } else if let blobId = blob.id { 333 } else if let blobId = blob.id {
334 await loadBlob(entry: entry, blobId: blobId) 334 await loadBlob(entry: entry, blobId: blobId)
335 } else {
336 viewingEntry = entry
337 viewingObject = object
338 } 335 }
339 336
340 case .unknown: 337 case .unknown:
Hutch/Views/Repositories/HgRepositorySettingsView.swift +2 −2
@@ -121,9 +121,9 @@ struct HgRepositorySettingsView: View {
121 .themedRow() 121 .themedRow()
122 122
123 Picker("Visibility", selection: Bindable(viewModel).editedVisibility) { 123 Picker("Visibility", selection: Bindable(viewModel).editedVisibility) {
124 Text("Public").tag(Visibility.public) 124 Text("Public").tag(Visibility.publicVisibility)
125 Text("Unlisted").tag(Visibility.unlisted) 125 Text("Unlisted").tag(Visibility.unlisted)
126 Text("Private").tag(Visibility.private) 126 Text("Private").tag(Visibility.privateVisibility)
127 } 127 }
128 .themedRow() 128 .themedRow()
129 129
Hutch/Views/Repositories/ReadmeView.swift +1 −1
@@ -1828,7 +1828,7 @@ private final class HTMLWebViewCoordinator: NSObject, WKNavigationDelegate, @unc
1828 } 1828 }
1829 1829
1830 func webView( 1830 func webView(
1831 _ webView: WKWebView, 1831 _: WKWebView,
1832 decidePolicyFor navigationAction: WKNavigationAction, 1832 decidePolicyFor navigationAction: WKNavigationAction,
1833 decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void 1833 decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void
1834 ) { 1834 ) {
Hutch/Views/Repositories/RepositoryListView.swift +3 −3
@@ -214,7 +214,7 @@ private struct CreateRepositorySheet: View {
214 @State private var name = "" 214 @State private var name = ""
215 @State private var description = "" 215 @State private var description = ""
216 @State private var cloneURL = "" 216 @State private var cloneURL = ""
217 @State private var visibility: Visibility = .public 217 @State private var visibility: Visibility = .publicVisibility
218 @State private var service: RepositoryCreationService = .git 218 @State private var service: RepositoryCreationService = .git
219 219
220 var body: some View { 220 var body: some View {
@@ -235,9 +235,9 @@ private struct CreateRepositorySheet: View {
235 .lineLimit(2...4) 235 .lineLimit(2...4)
236 .themedRow() 236 .themedRow()
237 Picker("Visibility", selection: $visibility) { 237 Picker("Visibility", selection: $visibility) {
238 Text("Public").tag(Visibility.public) 238 Text("Public").tag(Visibility.publicVisibility)
239 Text("Unlisted").tag(Visibility.unlisted) 239 Text("Unlisted").tag(Visibility.unlisted)
240 Text("Private").tag(Visibility.private) 240 Text("Private").tag(Visibility.privateVisibility)
241 } 241 }
242 .themedRow() 242 .themedRow()
243 } 243 }
Hutch/Views/Repositories/RepositoryListViewModel.swift +39 −56
@@ -397,15 +397,17 @@ final class RepositoryListViewModel {
397 397
398 func repositorySummary(service: SRHTService) -> RepositorySummary { 398 func repositorySummary(service: SRHTService) -> RepositorySummary {
399 RepositorySummary( 399 RepositorySummary(
400 id: id, 400 fields: .init(
401 rid: rid, 401 id: id,
402 service: service, 402 rid: rid,
403 name: name, 403 service: service,
404 description: description, 404 name: name,
405 visibility: visibility, 405 description: description,
406 updated: updated, 406 visibility: visibility,
407 owner: owner, 407 updated: updated,
408 head: head 408 owner: owner,
409 head: head
410 )
409 ) 411 )
410 } 412 }
411 } 413 }
@@ -422,15 +424,17 @@ final class RepositoryListViewModel {
422 424
423 func repositorySummary(service: SRHTService) -> RepositorySummary { 425 func repositorySummary(service: SRHTService) -> RepositorySummary {
424 RepositorySummary( 426 RepositorySummary(
425 id: id, 427 fields: .init(
426 rid: rid, 428 id: id,
427 service: service, 429 rid: rid,
428 name: name, 430 service: service,
429 description: description, 431 name: name,
430 visibility: visibility, 432 description: description,
431 updated: updated, 433 visibility: visibility,
432 owner: owner, 434 updated: updated,
433 head: tip.map { Reference(name: $0.branch, target: nil) } 435 owner: owner,
436 head: tip.map { Reference(name: $0.branch, target: nil) }
437 )
434 ) 438 )
435 } 439 }
436 } 440 }
@@ -463,17 +467,7 @@ final class RepositoryListViewModel {
463 } 467 }
464 468
465 if useCache && cursor == nil { 469 if useCache && cursor == nil {
466 switch service { 470 if service == .hg {
467 case .git:
468 let result = try await client.executeAndCache(
469 service: service,
470 query: Self.gitQuery,
471 variables: variables.isEmpty ? nil : variables,
472 responseType: RepositoriesResponse.self,
473 cacheKey: cacheKey(for: service)
474 )
475 return result.repositories ?? Self.emptyPage
476 case .hg:
477 let hgVariables = cursor.map { ["cursor": $0 as any Sendable] } 471 let hgVariables = cursor.map { ["cursor": $0 as any Sendable] }
478 let result = try await client.executeAndCache( 472 let result = try await client.executeAndCache(
479 service: service, 473 service: service,
@@ -497,27 +491,17 @@ final class RepositoryListViewModel {
497 } ?? [], 491 } ?? [],
498 cursor: result.repositories?.cursor 492 cursor: result.repositories?.cursor
499 ) 493 )
500 default:
501 let result = try await client.executeAndCache(
502 service: service,
503 query: Self.gitQuery,
504 variables: variables.isEmpty ? nil : variables,
505 responseType: RepositoriesResponse.self,
506 cacheKey: cacheKey(for: service)
507 )
508 return result.repositories ?? Self.emptyPage
509 } 494 }
495 let result = try await client.executeAndCache(
496 service: service,
497 query: Self.gitQuery,
498 variables: variables.isEmpty ? nil : variables,
499 responseType: RepositoriesResponse.self,
500 cacheKey: cacheKey(for: service)
501 )
502 return result.repositories ?? Self.emptyPage
510 } else { 503 } else {
511 switch service { 504 if service == .hg {
512 case .git:
513 let result = try await client.execute(
514 service: service,
515 query: Self.gitQuery,
516 variables: variables.isEmpty ? nil : variables,
517 responseType: RepositoriesResponse.self
518 )
519 return result.repositories ?? Self.emptyPage
520 case .hg:
521 let hgVariables = cursor.map { ["cursor": $0 as any Sendable] } 505 let hgVariables = cursor.map { ["cursor": $0 as any Sendable] }
522 let result = try await client.execute( 506 let result = try await client.execute(
523 service: service, 507 service: service,
@@ -540,15 +524,14 @@ final class RepositoryListViewModel {
540 } ?? [], 524 } ?? [],
541 cursor: result.repositories?.cursor 525 cursor: result.repositories?.cursor
542 ) 526 )
543 default:
544 let result = try await client.execute(
545 service: service,
546 query: Self.gitQuery,
547 variables: variables.isEmpty ? nil : variables,
548 responseType: RepositoriesResponse.self
549 )
550 return result.repositories ?? Self.emptyPage
551 } 527 }
528 let result = try await client.execute(
529 service: service,
530 query: Self.gitQuery,
531 variables: variables.isEmpty ? nil : variables,
532 responseType: RepositoriesResponse.self
533 )
534 return result.repositories ?? Self.emptyPage
552 } 535 }
553 } 536 }
554 537
Hutch/Views/Repositories/RepositoryRowView.swift +4 −4
@@ -154,17 +154,17 @@ struct VisibilityBadge: View {
154 154
155 private var label: String { 155 private var label: String {
156 switch visibility { 156 switch visibility {
157 case .public: "PUBLIC" 157 case .publicVisibility: "PUBLIC"
158 case .unlisted: "UNLISTED" 158 case .unlisted: "UNLISTED"
159 case .private: "PRIVATE" 159 case .privateVisibility: "PRIVATE"
160 } 160 }
161 } 161 }
162 162
163 private var color: Color { 163 private var color: Color {
164 switch visibility { 164 switch visibility {
165 case .public: .green 165 case .publicVisibility: .green
166 case .unlisted: .orange 166 case .unlisted: .orange
167 case .private: .red 167 case .privateVisibility: .red
168 } 168 }
169 } 169 }
170} 170}
Hutch/Views/Repositories/RepositorySettingsView.swift +4 −4
@@ -227,9 +227,9 @@ struct RepositorySettingsView: View {
227 private func visibilitySection(_ viewModel: RepositorySettingsViewModel) -> some View { 227 private func visibilitySection(_ viewModel: RepositorySettingsViewModel) -> some View {
228 Section { 228 Section {
229 Picker("Visibility", selection: Bindable(viewModel).editedVisibility) { 229 Picker("Visibility", selection: Bindable(viewModel).editedVisibility) {
230 Text("Public").tag(Visibility.public) 230 Text("Public").tag(Visibility.publicVisibility)
231 Text("Unlisted").tag(Visibility.unlisted) 231 Text("Unlisted").tag(Visibility.unlisted)
232 Text("Private").tag(Visibility.private) 232 Text("Private").tag(Visibility.privateVisibility)
233 } 233 }
234 .themedRow() 234 .themedRow()
235 235
@@ -283,11 +283,11 @@ struct RepositorySettingsView: View {
283 283
284 private func visibilityConfirmationMessage(for viewModel: RepositorySettingsViewModel) -> String { 284 private func visibilityConfirmationMessage(for viewModel: RepositorySettingsViewModel) -> String {
285 switch viewModel.editedVisibility { 285 switch viewModel.editedVisibility {
286 case .public: 286 case .publicVisibility:
287 "Anyone will be able to find and view this repository." 287 "Anyone will be able to find and view this repository."
288 case .unlisted: 288 case .unlisted:
289 "People with the link can view this repository, but it won't appear in public listings." 289 "People with the link can view this repository, but it won't appear in public listings."
290 case .private: 290 case .privateVisibility:
291 "Only people with explicit access will be able to view this repository." 291 "Only people with explicit access will be able to view this repository."
292 } 292 }
293 } 293 }
Hutch/Views/Repositories/RepositorySettingsViewModel.swift +11 −9
@@ -20,15 +20,17 @@ private struct UpdatedRepositoryPayload: Decodable, Sendable {
20 20
21 func repositorySummary(using owner: Entity, service: SRHTService) -> RepositorySummary { 21 func repositorySummary(using owner: Entity, service: SRHTService) -> RepositorySummary {
22 RepositorySummary( 22 RepositorySummary(
23 id: id, 23 fields: .init(
24 rid: rid, 24 id: id,
25 service: service, 25 rid: rid,
26 name: name, 26 service: service,
27 description: description, 27 name: name,
28 visibility: visibility, 28 description: description,
29 updated: updated, 29 visibility: visibility,
30 owner: owner, 30 updated: updated,
31 head: head 31 owner: owner,
32 head: head
33 )
32 ) 34 )
33 } 35 }
34} 36}
Hutch/Views/Repositories/RepositorySummarySupport.swift +2 −2
@@ -37,11 +37,11 @@ func repositoryCloneURLs(for repository: RepositorySummary) -> RepositoryCloneUR
37 37
38func repositoryVisibilityLabel(_ visibility: Visibility) -> String { 38func repositoryVisibilityLabel(_ visibility: Visibility) -> String {
39 switch visibility { 39 switch visibility {
40 case .public: 40 case .publicVisibility:
41 return "Public" 41 return "Public"
42 case .unlisted: 42 case .unlisted:
43 return "Unlisted" 43 return "Unlisted"
44 case .private: 44 case .privateVisibility:
45 return "Private" 45 return "Private"
46 } 46 }
47} 47}
Hutch/Views/Settings/SettingsViewModel.swift +6 −4
@@ -228,10 +228,12 @@ final class SettingsViewModel {
228 service: .meta, 228 service: .meta,
229 query: Self.updateUserMutation, 229 query: Self.updateUserMutation,
230 variables: ["input": input], 230 variables: ["input": input],
231 fileVariablePath: "input.avatar", 231 file: MultipartUploadFile(
232 fileData: jpegData, 232 variablePath: "input.avatar",
233 fileName: "avatar.jpg", 233 fileData: jpegData,
234 mimeType: "image/jpeg", 234 fileName: "avatar.jpg",
235 mimeType: "image/jpeg"
236 ),
235 responseType: UpdateUserResponse.self 237 responseType: UpdateUserResponse.self
236 ) 238 )
237 let updated = result.updateUser 239 let updated = result.updateUser
Hutch/Views/Tickets/TicketListView.swift +2
@@ -1400,11 +1400,13 @@ struct FlowLayout: Layout {
1400 var spacing: CGFloat = 4 1400 var spacing: CGFloat = 4
1401 1401
1402 func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { 1402 func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
1403 _ = cache
1403 let result = layoutSubviews(proposal: proposal, subviews: subviews) 1404 let result = layoutSubviews(proposal: proposal, subviews: subviews)
1404 return result.size 1405 return result.size
1405 } 1406 }
1406 1407
1407 func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { 1408 func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
1409 _ = cache
1408 let result = layoutSubviews(proposal: proposal, subviews: subviews) 1410 let result = layoutSubviews(proposal: proposal, subviews: subviews)
1409 for (index, position) in result.positions.enumerated() { 1411 for (index, position) in result.positions.enumerated() {
1410 subviews[index].place( 1412 subviews[index].place(
Hutch/Views/Tickets/TrackerListView.swift +1 −1
@@ -37,7 +37,7 @@ struct TrackerListView: View {
37 error: viewModel.error, 37 error: viewModel.error,
38 initialName: "", 38 initialName: "",
39 initialDescription: "", 39 initialDescription: "",
40 initialVisibility: .public 40 initialVisibility: .publicVisibility
41 ) { name, description, visibility in 41 ) { name, description, visibility in
42 if let tracker = await viewModel.createTracker( 42 if let tracker = await viewModel.createTracker(
43 name: name, 43 name: name,
Hutch/Views/Tickets/TrackerManagementView.swift +2 −2
@@ -659,9 +659,9 @@ struct TrackerEditorSheet: View {
659 .lineLimit(2...4) 659 .lineLimit(2...4)
660 .themedRow() 660 .themedRow()
661 Picker("Visibility", selection: $visibility) { 661 Picker("Visibility", selection: $visibility) {
662 Text("Public").tag(Visibility.public) 662 Text("Public").tag(Visibility.publicVisibility)
663 Text("Unlisted").tag(Visibility.unlisted) 663 Text("Unlisted").tag(Visibility.unlisted)
664 Text("Private").tag(Visibility.private) 664 Text("Private").tag(Visibility.privateVisibility)
665 } 665 }
666 .themedRow() 666 .themedRow()
667 } 667 }
HutchTests/AppStateTests.swift +12 −10
@@ -39,22 +39,24 @@ struct AppStateTests {
39 func navigationHelpersQueueExpectedTargets() { 39 func navigationHelpersQueueExpectedTargets() {
40 let appState = AppState() 40 let appState = AppState()
41 let repository = RepositorySummary( 41 let repository = RepositorySummary(
42 id: 1, 42 fields: .init(
43 rid: "repo", 43 id: 1,
44 service: .git, 44 rid: "repo",
45 name: "hutch", 45 service: .git,
46 description: nil, 46 name: "hutch",
47 visibility: .public, 47 description: nil,
48 updated: .distantPast, 48 visibility: .publicVisibility,
49 owner: Entity(canonicalName: "~owner"), 49 updated: .distantPast,
50 head: nil 50 owner: Entity(canonicalName: "~owner"),
51 head: nil
52 )
51 ) 53 )
52 let tracker = TrackerSummary( 54 let tracker = TrackerSummary(
53 id: 2, 55 id: 2,
54 rid: "tracker", 56 rid: "tracker",
55 name: "todo", 57 name: "todo",
56 description: nil, 58 description: nil,
57 visibility: .public, 59 visibility: .publicVisibility,
58 updated: .distantPast, 60 updated: .distantPast,
59 owner: Entity(canonicalName: "~owner") 61 owner: Entity(canonicalName: "~owner")
60 ) 62 )
HutchTests/ProjectTests.swift +6 −6
@@ -15,7 +15,7 @@ struct ProjectTests {
15 name: "Hutch", 15 name: "Hutch",
16 description: nil, 16 description: nil,
17 website: nil, 17 website: nil,
18 visibility: .public, 18 visibility: .publicVisibility,
19 tags: [], 19 tags: [],
20 updated: Date(timeIntervalSince1970: 0) 20 updated: Date(timeIntervalSince1970: 0)
21 ), 21 ),
@@ -25,7 +25,7 @@ struct ProjectTests {
25 id: "list-1", 25 id: "list-1",
26 name: "hutch-devel", 26 name: "hutch-devel",
27 description: nil, 27 description: nil,
28 visibility: .public, 28 visibility: .publicVisibility,
29 owner: Entity(canonicalName: "~owner") 29 owner: Entity(canonicalName: "~owner")
30 ) 30 )
31 ], 31 ],
@@ -34,7 +34,7 @@ struct ProjectTests {
34 id: "repo-1", 34 id: "repo-1",
35 name: "hutch", 35 name: "hutch",
36 description: nil, 36 description: nil,
37 visibility: .public, 37 visibility: .publicVisibility,
38 owner: Entity(canonicalName: "~owner"), 38 owner: Entity(canonicalName: "~owner"),
39 repoType: .git 39 repoType: .git
40 ), 40 ),
@@ -42,7 +42,7 @@ struct ProjectTests {
42 id: "repo-2", 42 id: "repo-2",
43 name: "hutch-web", 43 name: "hutch-web",
44 description: nil, 44 description: nil,
45 visibility: .public, 45 visibility: .publicVisibility,
46 owner: Entity(canonicalName: "~owner"), 46 owner: Entity(canonicalName: "~owner"),
47 repoType: .git 47 repoType: .git
48 ) 48 )
@@ -52,7 +52,7 @@ struct ProjectTests {
52 id: "tracker-1", 52 id: "tracker-1",
53 name: "bugs", 53 name: "bugs",
54 description: nil, 54 description: nil,
55 visibility: .public, 55 visibility: .publicVisibility,
56 owner: Entity(canonicalName: "~owner") 56 owner: Entity(canonicalName: "~owner")
57 ) 57 )
58 ], 58 ],
@@ -71,7 +71,7 @@ struct ProjectTests {
71 name: "Docs", 71 name: "Docs",
72 description: nil, 72 description: nil,
73 website: Fixture.exampleWebsite, 73 website: Fixture.exampleWebsite,
74 visibility: .public, 74 visibility: .publicVisibility,
75 tags: [], 75 tags: [],
76 updated: Date(timeIntervalSince1970: 0) 76 updated: Date(timeIntervalSince1970: 0)
77 ), 77 ),
HutchTests/RepositoryACLViewModelTests.swift +11 −9
@@ -110,15 +110,17 @@ struct RepositoryACLViewModelTests {
110 @MainActor 110 @MainActor
111 private func makeRepository() -> RepositorySummary { 111 private func makeRepository() -> RepositorySummary {
112 RepositorySummary( 112 RepositorySummary(
113 id: 1, 113 fields: .init(
114 rid: "rid-1", 114 id: 1,
115 service: .git, 115 rid: "rid-1",
116 name: "repo", 116 service: .git,
117 description: nil, 117 name: "repo",
118 visibility: .public, 118 description: nil,
119 updated: .now, 119 visibility: .publicVisibility,
120 owner: Entity(canonicalName: "~owner"), 120 updated: .now,
121 head: nil 121 owner: Entity(canonicalName: "~owner"),
122 head: nil
123 )
122 ) 124 )
123 } 125 }
124} 126}
HutchTests/RepositoryListViewModelTests.swift +11 −9
@@ -79,15 +79,17 @@ struct RepositoryListViewModelTests {
79 branch: String = "main" 79 branch: String = "main"
80 ) -> RepositorySummary { 80 ) -> RepositorySummary {
81 RepositorySummary( 81 RepositorySummary(
82 id: id, 82 fields: .init(
83 rid: "rid-\(id)", 83 id: id,
84 service: service, 84 rid: "rid-\(id)",
85 name: name, 85 service: service,
86 description: description, 86 name: name,
87 visibility: .public, 87 description: description,
88 updated: Date(timeIntervalSince1970: TimeInterval(id)), 88 visibility: .publicVisibility,
89 owner: Entity(canonicalName: owner), 89 updated: Date(timeIntervalSince1970: TimeInterval(id)),
90 head: Reference(name: branch, target: nil) 90 owner: Entity(canonicalName: owner),
91 head: Reference(name: branch, target: nil)
92 )
91 ) 93 )
92 } 94 }
93} 95}
HutchTests/RepositorySettingsViewModelTests.swift +11 −9
@@ -118,15 +118,17 @@ struct RepositorySettingsViewModelTests {
118 @MainActor 118 @MainActor
119 private func makeRepository(headName: String?) -> RepositorySummary { 119 private func makeRepository(headName: String?) -> RepositorySummary {
120 RepositorySummary( 120 RepositorySummary(
121 id: 1, 121 fields: .init(
122 rid: "rid-1", 122 id: 1,
123 service: .git, 123 rid: "rid-1",
124 name: "repo", 124 service: .git,
125 description: "desc", 125 name: "repo",
126 visibility: .public, 126 description: "desc",
127 updated: .now, 127 visibility: .publicVisibility,
128 owner: Entity(canonicalName: "~owner"), 128 updated: .now,
129 head: headName.map { Reference(name: $0, target: nil) } 129 owner: Entity(canonicalName: "~owner"),
130 head: headName.map { Reference(name: $0, target: nil) }
131 )
130 ) 132 )
131 } 133 }
132} 134}
HutchTests/SRHTWebURLTests.swift +12 −10
@@ -14,22 +14,24 @@ struct SRHTWebURLTests {
14 } 14 }
15 15
16 private let repository = RepositorySummary( 16 private let repository = RepositorySummary(
17 id: 1, 17 fields: .init(
18 rid: "repo-1", 18 id: 1,
19 service: .git, 19 rid: "repo-1",
20 name: "hutch", 20 service: .git,
21 description: nil, 21 name: "hutch",
22 visibility: .public, 22 description: nil,
23 updated: .distantPast, 23 visibility: .publicVisibility,
24 owner: Entity(canonicalName: "~ccleberg"), 24 updated: .distantPast,
25 head: nil 25 owner: Entity(canonicalName: "~ccleberg"),
26 head: nil
27 )
26 ) 28 )
27 private let tracker = TrackerSummary( 29 private let tracker = TrackerSummary(
28 id: 2, 30 id: 2,
29 rid: "tracker-1", 31 rid: "tracker-1",
30 name: "todo", 32 name: "todo",
31 description: nil, 33 description: nil,
32 visibility: .public, 34 visibility: .publicVisibility,
33 updated: .distantPast, 35 updated: .distantPast,
34 owner: Entity(canonicalName: "~ccleberg") 36 owner: Entity(canonicalName: "~ccleberg")
35 ) 37 )
HutchTests/TrackerListViewModelTests.swift +1 −1
@@ -66,7 +66,7 @@ struct TrackerListViewModelTests {
66 rid: "rid-\(id)", 66 rid: "rid-\(id)",
67 name: name, 67 name: name,
68 description: description, 68 description: description,
69 visibility: .public, 69 visibility: .publicVisibility,
70 updated: Date(), 70 updated: Date(),
71 owner: Entity(canonicalName: owner) 71 owner: Entity(canonicalName: owner)
72 ) 72 )