diff options
| author | Christian Cleberg <[email protected]> | 2026-04-13 20:32:40 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-13 20:32:40 -0500 |
| commit | d6968ea122d910b432bd539cf2fa3d1cee962fdb (patch) | |
| tree | b5fe9a85880d2a153a2a9d4ee8f1ab2156f64d25 | |
| parent | 312e535f400f31714b3750de5222a1f6a8e5bcda (diff) | |
| download | hutch-3.1.5.tar.gz hutch-3.1.5.tar.bz2 hutch-3.1.5.zip | |
fix: more sonarqube quality fixesv3.1.5
| -rw-r--r-- | Hutch.xcodeproj/project.pbxproj | 16 | ||||
| -rw-r--r-- | Hutch/Networking/SRHTClient.swift | 25 | ||||
| -rw-r--r-- | Hutch/Views/Builds/BuildListViewModel.swift | 5 | ||||
| -rw-r--r-- | Hutch/Views/Pastes/PasteListView.swift | 8 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/CommitDetailViewModel.swift | 9 | ||||
| -rw-r--r-- | Hutch/Views/Repositories/FileTreeViewModel.swift | 8 |
6 files changed, 40 insertions, 31 deletions
diff --git a/Hutch.xcodeproj/project.pbxproj b/Hutch.xcodeproj/project.pbxproj index 3162b32..68ef58c 100644 --- a/Hutch.xcodeproj/project.pbxproj +++ b/Hutch.xcodeproj/project.pbxproj @@ -515,7 +515,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = ZCNAX3VL9D; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -532,7 +532,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.1.4; + MARKETING_VERSION = 3.1.5; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -552,7 +552,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = ZCNAX3VL9D; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -569,7 +569,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 3.1.4; + MARKETING_VERSION = 3.1.5; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -632,7 +632,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = ZCNAX3VL9D; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = HutchWidgetExtension/Info.plist; @@ -642,7 +642,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.1.4; + MARKETING_VERSION = 3.1.5; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -661,7 +661,7 @@ APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 72; + CURRENT_PROJECT_VERSION = 73; DEVELOPMENT_TEAM = ZCNAX3VL9D; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = HutchWidgetExtension/Info.plist; @@ -671,7 +671,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 3.1.4; + MARKETING_VERSION = 3.1.5; PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/Hutch/Networking/SRHTClient.swift b/Hutch/Networking/SRHTClient.swift index fa7b26b..70c7650 100644 --- a/Hutch/Networking/SRHTClient.swift +++ b/Hutch/Networking/SRHTClient.swift @@ -23,13 +23,13 @@ final class SRHTClient: Sendable { /// The personal access token used for `Authorization: Bearer` headers. /// Loaded from Keychain on init; can be refreshed via ``reloadToken()``. - private let _token: OSAllocatedUnfairLock<String?> + private let tokenLock: OSAllocatedUnfairLock<String?> /// In-memory response cache for stale-while-revalidate pattern. let responseCache = ResponseCache() var hasToken: Bool { - _token.withLock { $0 != nil } + tokenLock.withLock { $0 != nil } } init(session: URLSession = .shared, token: String? = nil) { @@ -37,12 +37,12 @@ final class SRHTClient: Sendable { self.decoder = JSONDecoder() self.decoder.dateDecodingStrategy = .srhtFlexible self.encoder = JSONEncoder() - self._token = OSAllocatedUnfairLock(initialState: token) + self.tokenLock = OSAllocatedUnfairLock(initialState: token) } /// Update the stored token (e.g. after the user saves a new one in Keychain). func setToken(_ token: String?) { - _token.withLock { $0 = token } + tokenLock.withLock { $0 = token } } /// Execute a GraphQL query or mutation against a SourceHut service. @@ -59,7 +59,7 @@ final class SRHTClient: Sendable { variables: [String: any Sendable]? = nil, responseType _: T.Type ) async throws -> T { - guard let token = _token.withLock({ $0 }), !token.isEmpty else { + guard let token = tokenLock.withLock({ $0 }), !token.isEmpty else { throw SRHTError.unauthorized } @@ -173,7 +173,7 @@ final class SRHTClient: Sendable { file: MultipartUploadFile, responseType _: T.Type ) async throws -> T { - guard let token = _token.withLock({ $0 }), !token.isEmpty else { + guard let token = tokenLock.withLock({ $0 }), !token.isEmpty else { throw SRHTError.unauthorized } @@ -307,7 +307,7 @@ final class SRHTClient: Sendable { files: [MultipartUploadFile], responseType _: T.Type ) async throws -> T { - guard let token = _token.withLock({ $0 }), !token.isEmpty else { + guard let token = tokenLock.withLock({ $0 }), !token.isEmpty else { throw SRHTError.unauthorized } @@ -417,7 +417,7 @@ final class SRHTClient: Sendable { service: service, query: query, variables: variables, - responseType: responseType, + responseType: T.self, cacheKey: cacheKey ) } @@ -430,7 +430,7 @@ final class SRHTClient: Sendable { responseType _: T.Type, cacheKey: String ) async throws -> T { - guard let token = _token.withLock({ $0 }), !token.isEmpty else { + guard let token = tokenLock.withLock({ $0 }), !token.isEmpty else { throw SRHTError.unauthorized } @@ -527,7 +527,7 @@ final class SRHTClient: Sendable { /// Fetch the contents of a URL as plain text, using the same authorization header. /// Used for build logs and other non-GraphQL resources. func fetchText(url: URL) async throws -> String { - guard let token = _token.withLock({ $0 }), !token.isEmpty else { + guard let token = tokenLock.withLock({ $0 }), !token.isEmpty else { throw SRHTError.unauthorized } guard Self.isTrustedAuthenticatedTextURL(url) else { @@ -593,12 +593,13 @@ final class SRHTClient: Sendable { resultKeyPath: String ) async throws -> [T] { var all: [T] = [] - for try await element in paginated( + let pages: SRHTPaginatedSequence<T> = paginated( service: service, query: query, variables: variables, resultKeyPath: resultKeyPath - ) { + ) + for try await element in pages { all.append(element) } return all diff --git a/Hutch/Views/Builds/BuildListViewModel.swift b/Hutch/Views/Builds/BuildListViewModel.swift index 643bacd..cf5d786 100644 --- a/Hutch/Views/Builds/BuildListViewModel.swift +++ b/Hutch/Views/Builds/BuildListViewModel.swift @@ -182,12 +182,13 @@ final class BuildListViewModel { /// Fetch the first page of jobs. Shows cached data instantly if available, /// then refreshes from the network in the background. func loadJobs() async { - // Show cached data immediately on first load + // Show cached data immediately on first load (may populate `jobs` from cache). if jobs.isEmpty { loadFromCache() } - if jobs.isEmpty { + let treatAsInitialLoad = jobs.isEmpty + if treatAsInitialLoad { isLoading = true } else { isRefreshing = true diff --git a/Hutch/Views/Pastes/PasteListView.swift b/Hutch/Views/Pastes/PasteListView.swift index 17bb8ac..b325153 100644 --- a/Hutch/Views/Pastes/PasteListView.swift +++ b/Hutch/Views/Pastes/PasteListView.swift @@ -276,14 +276,14 @@ private struct CreatePasteSheet: View { NavigationStack { Form { Section("Files") { - ForEach($files) { $file in + ForEach($files) { fileBinding in VStack(alignment: .leading, spacing: 8) { - TextField("Filename (optional)", text: $file.filename) + TextField("Filename (optional)", text: fileBinding.filename) .autocorrectionDisabled() .textInputAutocapitalization(.never) ZStack(alignment: .topLeading) { - if file.contents.isEmpty { + if fileBinding.wrappedValue.contents.isEmpty { Text("Paste contents") .foregroundStyle(.tertiary) .padding(.top, 8) @@ -291,7 +291,7 @@ private struct CreatePasteSheet: View { .allowsHitTesting(false) } - TextEditor(text: $file.contents) + TextEditor(text: fileBinding.contents) .font(.system(.body, design: .monospaced)) .frame(minHeight: 180) } diff --git a/Hutch/Views/Repositories/CommitDetailViewModel.swift b/Hutch/Views/Repositories/CommitDetailViewModel.swift index f0898f5..92fb915 100644 --- a/Hutch/Views/Repositories/CommitDetailViewModel.swift +++ b/Hutch/Views/Repositories/CommitDetailViewModel.swift @@ -7,8 +7,11 @@ private struct CommitResponse: Decodable, Sendable { } private struct CommitRepository: Decodable, Sendable { - // swiftlint:disable:next identifier_name - let revparse_single: CommitDetail + let revparseSingle: CommitDetail + + enum CodingKeys: String, CodingKey { + case revparseSingle = "revparse_single" + } } // MARK: - View Model @@ -66,7 +69,7 @@ final class CommitDetailViewModel { do { let result = try await executeWithRetry() - commit = result.repository?.revparse_single + commit = result.repository?.revparseSingle } catch { self.error = error.userFacingMessage } diff --git a/Hutch/Views/Repositories/FileTreeViewModel.swift b/Hutch/Views/Repositories/FileTreeViewModel.swift index 98211bf..7330cd8 100644 --- a/Hutch/Views/Repositories/FileTreeViewModel.swift +++ b/Hutch/Views/Repositories/FileTreeViewModel.swift @@ -7,7 +7,11 @@ private struct RevparseResponse: Decodable, Sendable { } private struct RevparseRepository: Decodable, Sendable { - let revparse_single: RevparseCommit? + let revparseSingle: RevparseCommit? + + enum CodingKeys: String, CodingKey { + case revparseSingle = "revparse_single" + } } private struct RevparseCommit: Decodable, Sendable { @@ -277,7 +281,7 @@ final class FileTreeViewModel { } throw error } - if let tree = result.repository?.revparse_single?.tree, + if let tree = result.repository?.revparseSingle?.tree, let rootId = tree.id { navStack = [FileNavEntry(name: "root", treeId: rootId)] var allEntries = tree.entries?.results ?? [] |
