Commit fec160e859
fec160e859db3341cfaf8920b4f29712db4dd7f5
parent: 9e848efa90
Unsigned
cmc <hello@cleberg.net> · 2026-07-16 15:18 UTC
chore: clear the actionable SonarCloud code smells
- S1871: merge the identical .home / .recentActivity deep-link cases in
RootView — recent activity is a section of Home, not its own screen.
- S1186: comment the two intentionally-empty Cancel buttons
(PatchsetDetailView, TicketDetailView) and the empty URLProtocol
stopLoading override in APICacheTests.
- S108: comment the expected-miss catch block in APICacheTests.
- S1172: rename the unused url parameter in mimeType(for:) to _.
- S4624: extract the nested template literal in the deep-link builders
(background.js, content.js) to a pathSegment variable.
Left as Won't Fix, with reasons: the 35 hardcoded-URI warnings (a
one-forge client and its literal-URL tests), executeCached's 8 params
(38 call sites, no benefit), the forceRefresh S1172 pair (fixed as a
real bug instead), S1481 on ArtifactsView (false positive — $vm.error
is used), and S7785 (top-level await would break a classic content
script).
Layout: unified · split
Hutch/App/RootView.swift
+3 −5
| @@ -198,11 +198,9 @@ struct RootView: View { |
| 198 | } |
198 | } |
| 199 | |
199 | |
| 200 | switch link { |
200 | switch link { |
| 201 | case .home: |
201 | // Recent activity is a section of the Home tab, not a screen of its |
| 202 | homePath = NavigationPath() |
202 | // own, so its intent/widget deep link lands on Home like .home does. |
| 203 | appState.selectedTab = .home |
203 | case .home, .recentActivity: |
| 204 | |
| |
| 205 | case .recentActivity: |
| |
| 206 | homePath = NavigationPath() |
204 | homePath = NavigationPath() |
| 207 | appState.selectedTab = .home |
205 | appState.selectedTab = .home |
| 208 | |
206 | |
Hutch/Views/Patchsets/PatchsetDetailView.swift
+1 −1
| @@ -71,7 +71,7 @@ struct PatchsetDetailView: View { |
| 71 | Task { await viewModel.updateStatus(to: status) } |
71 | Task { await viewModel.updateStatus(to: status) } |
| 72 | } |
72 | } |
| 73 | } |
73 | } |
| 74 | Button("Cancel", role: .cancel) {} |
74 | Button("Cancel", role: .cancel) {} // dismisses the dialog; no action needed |
| 75 | } |
75 | } |
| 76 | .alert( |
76 | .alert( |
| 77 | "Couldn't Update Patchset", |
77 | "Couldn't Update Patchset", |
Hutch/Views/Repositories/RepositoryDetailViewModel.swift
+1 −1
| @@ -627,7 +627,7 @@ final class RepositoryDetailViewModel { |
| 627 | |
627 | |
| 628 | /// Artifacts are release tarballs and signatures rather than media, so a |
628 | /// Artifacts are release tarballs and signatures rather than media, so a |
| 629 | /// generic binary type is honest more often than guessing from the extension. |
629 | /// generic binary type is honest more often than guessing from the extension. |
| 630 | private nonisolated static func mimeType(for url: URL) -> String { |
630 | private nonisolated static func mimeType(for _: URL) -> String { |
| 631 | "application/octet-stream" |
631 | "application/octet-stream" |
| 632 | } |
632 | } |
| 633 | |
633 | |
Hutch/Views/Tickets/TicketDetailView.swift
+1 −1
| @@ -204,7 +204,7 @@ struct TicketDetailView: View { |
| 204 | } |
204 | } |
| 205 | } |
205 | } |
| 206 | } |
206 | } |
| 207 | Button("Cancel", role: .cancel) {} |
207 | Button("Cancel", role: .cancel) {} // dismisses the dialog; no action needed |
| 208 | } message: { |
208 | } message: { |
| 209 | Text("This permanently deletes the ticket and its comments. This cannot be undone.") |
209 | Text("This permanently deletes the ticket and its comments. This cannot be undone.") |
| 210 | } |
210 | } |
HutchSafariExtension/Resources/background.js
+2 −1
| @@ -68,7 +68,8 @@ function hutchDeepLinkFor(rawURL) { |
| 68 | |
68 | |
| 69 | const path = deepLinkPath(url.hostname, normalizedPath(url.pathname)); |
69 | const path = deepLinkPath(url.hostname, normalizedPath(url.pathname)); |
| 70 | const service = deepLinkService(url.hostname, path); |
70 | const service = deepLinkService(url.hostname, path); |
| 71 | return `hutch://${service}${path ? `/${path}` : ""}${url.search}${url.hash}`; |
71 | const pathSegment = path ? `/${path}` : ""; |
| |
72 | return `hutch://${service}${pathSegment}${url.search}${url.hash}`; |
| 72 | } |
73 | } |
| 73 | |
74 | |
| 74 | function showUnsupportedMessage(tabId) { |
75 | function showUnsupportedMessage(tabId) { |
HutchSafariExtension/Resources/content.js
+2 −1
| @@ -63,7 +63,8 @@ function hutchDeepLinkForLocation() { |
| 63 | |
63 | |
| 64 | const path = hutchDeepLinkPath(location.hostname, hutchNormalizedPath(location.pathname)); |
64 | const path = hutchDeepLinkPath(location.hostname, hutchNormalizedPath(location.pathname)); |
| 65 | const service = hutchDeepLinkService(location.hostname, path); |
65 | const service = hutchDeepLinkService(location.hostname, path); |
| 66 | return `hutch://${service}${path ? `/${path}` : ""}${location.search}${location.hash}`; |
66 | const pathSegment = path ? `/${path}` : ""; |
| |
67 | return `hutch://${service}${pathSegment}${location.search}${location.hash}`; |
| 67 | } |
68 | } |
| 68 | |
69 | |
| 69 | function storageGet(defaults) { |
70 | function storageGet(defaults) { |
HutchTests/APICacheTests.swift
+2 −1
| @@ -256,6 +256,7 @@ struct APICacheTests { |
| 256 | _ = try await cache.read(cacheKey: key) |
256 | _ = try await cache.read(cacheKey: key) |
| 257 | Issue.record("Expected cache miss for \(key).") |
257 | Issue.record("Expected cache miss for \(key).") |
| 258 | } catch APICacheError.miss { |
258 | } catch APICacheError.miss { |
| |
259 | // expected: a miss is the success path here |
| 259 | } catch { |
260 | } catch { |
| 260 | Issue.record("Unexpected error for \(key): \(error).") |
261 | Issue.record("Unexpected error for \(key): \(error).") |
| 261 | } |
262 | } |
| @@ -293,7 +294,7 @@ private final class CachedURLProtocol: URLProtocol, @unchecked Sendable { |
| 293 | } |
294 | } |
| 294 | } |
295 | } |
| 295 | |
296 | |
| 296 | override func stopLoading() {} |
297 | override func stopLoading() {} // required override; nothing to tear down |
| 297 | |
298 | |
| 298 | static func reset(responses: [CachedURLProtocolResponse], responseDelay: TimeInterval = 0) { |
299 | static func reset(responses: [CachedURLProtocolResponse], responseDelay: TimeInterval = 0) { |
| 299 | Self.responses = responses |
300 | Self.responses = responses |