gitbay/MRs/MRCreateViewModel.swift
61 lines · 1958 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 var draft = false
17 var format: String?
18
19 private let client: GitbayClient
20 let repoPath: String
21
22 init(client: GitbayClient, repoPath: String) {
23 self.client = client
24 self.repoPath = repoPath
25 }
26
27 func loadDefaultBranch() async {
28 guard defaultBranch == nil else { return }
29 defaultBranch = (try? await client.read(
30 ["repo", "show", repoPath], as: RepoDetail.self
31 ))?.defaultBranch
32 }
33
34 nonisolated private struct Created: Decodable, Sendable {
35 let number: Int64
36 }
37
38 func create(source: String, target: String, title: String, body: String) async -> Int64? {
39 working = true
40 errorMessage = nil
41 defer { working = false }
42 do {
43 var argv = ["mr", "create", repoPath,
44 "--source", source, "--target", target, "--title", title]
45 var stdin: String?
46 if !body.isEmpty {
47 argv.append(contentsOf: ["--file", "-"])
48 stdin = body
49 }
50 if let format { argv.append(contentsOf: ["--format", format]) }
51 if draft { argv.append("--draft") }
52 let created = try await client.run(argv, stdin: stdin, as: Created.self)
53 return created?.number
54 } catch let error as GitbayError {
55 errorMessage = error.userFacingMessage
56 } catch {
57 errorMessage = GitbayError.transport(error).userFacingMessage
58 }
59 return nil
60 }
61}