summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-13 20:32:40 -0500
committerChristian Cleberg <[email protected]>2026-04-13 20:32:40 -0500
commitd6968ea122d910b432bd539cf2fa3d1cee962fdb (patch)
treeb5fe9a85880d2a153a2a9d4ee8f1ab2156f64d25
parent312e535f400f31714b3750de5222a1f6a8e5bcda (diff)
downloadhutch-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.pbxproj16
-rw-r--r--Hutch/Networking/SRHTClient.swift25
-rw-r--r--Hutch/Views/Builds/BuildListViewModel.swift5
-rw-r--r--Hutch/Views/Pastes/PasteListView.swift8
-rw-r--r--Hutch/Views/Repositories/CommitDetailViewModel.swift9
-rw-r--r--Hutch/Views/Repositories/FileTreeViewModel.swift8
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 ?? []