Commit e61ef1ad41

e61ef1ad41492d11be106311cba422b886475fea

parent: 0e79b13ed6

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-06 23:45 UTC

Clear notice alongside actionError in RepoActionsViewModel

perform(_:) and fork(named:) reset actionError but left notice stale,
so a successful watch followed by a refused fork showed both a success
and a failure banner at once. Matches AccountViewModel.perform's shape.

Layout: unified · split

gitbay/Repos/RepoActionsViewModel.swift +2
@@ -85,6 +85,7 @@ final class RepoActionsViewModel {
8585 }
8686 working = true
8787 actionError = nil
88 notice = nil
8889 defer { working = false }
8990 do {
9091 return try await client.run(argv, as: ForkResult.self)
@@ -100,6 +101,7 @@ final class RepoActionsViewModel {
100101 private func perform(_ argv: [String]) async {
101102 working = true
102103 actionError = nil
104 notice = nil
103105 defer { working = false }
104106 do {
105107 try await client.run(argv)
gitbayTests/RepoActionTests.swift +21
@@ -161,4 +161,25 @@ struct RepoActionsTests {
161161 #expect(model.actionError?.isEmpty == false)
162162 #expect(model.working == false)
163163 }
164
165 /// A stale `notice` from an earlier success must not survive a later
166 /// failure — the screen must never show a success banner and a
167 /// failure banner at once.
168 @Test func aFailedActionClearsAStaleNotice() async throws {
169 let (client, stub) = try makeClient()
170 let model = RepoActionsViewModel(client: client, repoPath: "krz/gitbay")
171
172 stub.enqueue(.init(status: 200, json: ok))
173 await model.watch()
174 #expect(model.notice != nil)
175
176 stub.enqueue(.init(status: 200, json: """
177 {"protocol_version":1,"error":"a repository named gitbay already exists",\
178 "exit_code":1}
179 """))
180 _ = await model.fork(named: nil)
181
182 #expect(model.notice == nil)
183 #expect(model.actionError?.isEmpty == false)
184 }
164185}