gitbay/MRs/MRCreateViewModel.swift
57 lines · 1788 bytes
1import Foundation
2import Observation
3
4/// `mr create <repo> --source <b> --target <b> --title <t> --file -`.
5///
6/// Branch names are typed, not picked: no command lists branches yet
7/// (krz/gitbay#45). The target prefills with the default branch from
8/// `repo show`.
9@Observable
10@MainActor
11final class MRCreateViewModel {
12
13 private(set) var working = false
14 private(set) var errorMessage: String?
15 private(set) var defaultBranch: String?
16
17 private let client: GitbayClient
18 let repoPath: String
19
20 init(client: GitbayClient, repoPath: String) {
21 self.client = client
22 self.repoPath = repoPath
23 }
24
25 func loadDefaultBranch() async {
26 guard defaultBranch == nil else { return }
27 defaultBranch = (try? await client.read(
28 ["repo", "show", repoPath], as: RepoDetail.self
29 ))?.defaultBranch
30 }
31
32 nonisolated private struct Created: Decodable, Sendable {
33 let number: Int64
34 }
35
36 func create(source: String, target: String, title: String, body: String) async -> Int64? {
37 working = true
38 errorMessage = nil
39 defer { working = false }
40 do {
41 var argv = ["mr", "create", repoPath,
42 "--source", source, "--target", target, "--title", title]
43 var stdin: String?
44 if !body.isEmpty {
45 argv.append(contentsOf: ["--file", "-"])
46 stdin = body
47 }
48 let created = try await client.run(argv, stdin: stdin, as: Created.self)
49 return created?.number
50 } catch let error as GitbayError {
51 errorMessage = error.userFacingMessage
52 } catch {
53 errorMessage = GitbayError.transport(error).userFacingMessage
54 }
55 return nil
56 }
57}