From 32ad6cab8d58d99ebd8a28e8fa6e6f4e587cb1e5 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Tue, 17 Mar 2026 23:19:43 -0500 Subject: v1.0 --- .../Views/Repositories/CommitDetailViewModel.swift | 102 +++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 Hutch/Views/Repositories/CommitDetailViewModel.swift (limited to 'Hutch/Views/Repositories/CommitDetailViewModel.swift') diff --git a/Hutch/Views/Repositories/CommitDetailViewModel.swift b/Hutch/Views/Repositories/CommitDetailViewModel.swift new file mode 100644 index 0000000..5a8a23d --- /dev/null +++ b/Hutch/Views/Repositories/CommitDetailViewModel.swift @@ -0,0 +1,102 @@ +import Foundation + +// MARK: - Response types (file-private to avoid @MainActor Decodable issues) + +private struct CommitResponse: Decodable, Sendable { + let repository: CommitRepository? +} + +private struct CommitRepository: Decodable, Sendable { + // swiftlint:disable:next identifier_name + let revparse_single: CommitDetail +} + +// MARK: - View Model + +@Observable +@MainActor +final class CommitDetailViewModel { + + let repositoryRid: String + let service: SRHTService + private let client: SRHTClient + + private(set) var commit: CommitDetail? + private(set) var isLoading = false + var error: String? + + init(repositoryRid: String, service: SRHTService, commitId: String, client: SRHTClient) { + self.repositoryRid = repositoryRid + self.service = service + self.commitId = commitId + self.client = client + } + + private let commitId: String + + // MARK: - Query + + private static let query = """ + query commit($rid: ID!, $id: String!) { + repository(rid: $rid) { + revparse_single(revspec: $id) { + id + shortId + author { name email time } + committer { name email time } + message + diff + trailers { name value } + parents { id shortId author { name } } + tree { + entries { + results { id name mode object { type id shortId } } + cursor + } + } + } + } + } + """ + + func loadCommit() async { + guard !isLoading else { return } + isLoading = true + error = nil + + do { + let result = try await executeWithRetry() + commit = result.repository?.revparse_single + } catch { + self.error = error.localizedDescription + } + + isLoading = false + } + + /// Execute the commit query, retrying once after a 1-second delay on 502/503. + private func executeWithRetry() async throws -> CommitResponse { + do { + return try await client.execute( + service: service, + query: Self.query, + variables: [ + "rid": repositoryRid, + "id": commitId + ], + responseType: CommitResponse.self + ) + } catch let SRHTError.httpError(code) where code == 502 || code == 503 { + try await Task.sleep(for: .seconds(1)) + return try await client.execute( + service: service, + query: Self.query, + variables: [ + "rid": repositoryRid, + "id": commitId + ], + responseType: CommitResponse.self + ) + } + } +} -- cgit v1.2.3