Commit 14b8a9abb8
14b8a9abb840f47582ceca3a756cb9009e1340d6
parent: 3d76c278d1
Unsigned
cmc <hello@cleberg.net> · 2026-08-27 06:41 UTC
fix: stdin-carrying writes need --file - in argv
bodyFrom only reads stdin when argv says --file -; without it the
inline message wins and an empty one is a usage error. Verified against
production: issue comment with bare stdin returns exit 2 'empty
comment', with --file - it lands. Fixes mr comment, mr diff-comment
--reply, and issue comment, which all sent bare stdin.
Ref #11
Layout: unified · split
gitbay/Issues/IssueDetailViewModel.swift
+2 −1
| @@ -32,7 +32,8 @@ final class IssueDetailViewModel { |
| 32 | } |
32 | } |
| 33 | |
33 | |
| 34 | func comment(_ text: String) async { |
34 | func comment(_ text: String) async { |
| 35 | await perform(["issue", "comment"] + ref, stdin: text) |
35 | // stdin is only read when argv carries --file -. |
| |
36 | await perform(["issue", "comment"] + ref + ["--file", "-"], stdin: text) |
| 36 | } |
37 | } |
| 37 | |
38 | |
| 38 | func close() async { |
39 | func close() async { |
gitbay/MRs/MRDetailViewModel.swift
+4 −3
| @@ -59,8 +59,9 @@ final class MRDetailViewModel { |
| 59 | } |
59 | } |
| 60 | |
60 | |
| 61 | func comment(_ text: String) async { |
61 | func comment(_ text: String) async { |
| 62 | // Long text goes in stdin, the CLI's --file - discipline. |
62 | // Long text travels in stdin, but the server only reads it when |
| 63 | await perform(["mr", "comment"] + ref, stdin: text) |
63 | // argv says so: --file - is required, not implied. |
| |
64 | await perform(["mr", "comment"] + ref + ["--file", "-"], stdin: text) |
| 64 | } |
65 | } |
| 65 | |
66 | |
| 66 | func merge(strategy: String? = nil) async { |
67 | func merge(strategy: String? = nil) async { |
| @@ -79,7 +80,7 @@ final class MRDetailViewModel { |
| 79 | |
80 | |
| 80 | func reply(to thread: ReviewThread, _ text: String) async { |
81 | func reply(to thread: ReviewThread, _ text: String) async { |
| 81 | await perform( |
82 | await perform( |
| 82 | ["mr", "diff-comment"] + ref + ["--reply", String(thread.id)], |
83 | ["mr", "diff-comment"] + ref + ["--reply", String(thread.id), "--file", "-"], |
| 83 | stdin: text |
84 | stdin: text |
| 84 | ) |
85 | ) |
| 85 | } |
86 | } |
gitbayTests/IssueBuildViewModelTests.swift
+1 −1
| @@ -87,7 +87,7 @@ struct IssueDetailViewModelTests { |
| 87 | let write = stub.seen[1] |
87 | let write = stub.seen[1] |
| 88 | #expect(write.method == "POST") |
88 | #expect(write.method == "POST") |
| 89 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
89 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
| 90 | #expect(body["argv"] as? [String] == ["issue", "comment", "krz/gitbay", "11"]) |
90 | #expect(body["argv"] as? [String] == ["issue", "comment", "krz/gitbay", "11", "--file", "-"]) |
| 91 | #expect(body["stdin"] as? String == "triaged from the phone") |
91 | #expect(body["stdin"] as? String == "triaged from the phone") |
| 92 | } |
92 | } |
| 93 | |
93 | |
gitbayTests/MRViewModelTests.swift
+2 −2
| @@ -228,7 +228,7 @@ struct MRDetailViewModelTests { |
| 228 | |
228 | |
| 229 | let write = stub.seen[3] |
229 | let write = stub.seen[3] |
| 230 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
230 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
| 231 | #expect(body["argv"] as? [String] == ["mr", "comment", "krz/gitbay", "7"]) |
231 | #expect(body["argv"] as? [String] == ["mr", "comment", "krz/gitbay", "7", "--file", "-"]) |
| 232 | #expect(body["stdin"] as? String == "long review text\nwith lines") |
232 | #expect(body["stdin"] as? String == "long review text\nwith lines") |
| 233 | } |
233 | } |
| 234 | |
234 | |
| @@ -273,7 +273,7 @@ struct MRDetailViewModelTests { |
| 273 | let write = stub.seen[3] |
273 | let write = stub.seen[3] |
| 274 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
274 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
| 275 | #expect(body["argv"] as? [String] == |
275 | #expect(body["argv"] as? [String] == |
| 276 | ["mr", "diff-comment", "krz/gitbay", "7", "--reply", "3"]) |
276 | ["mr", "diff-comment", "krz/gitbay", "7", "--reply", "3", "--file", "-"]) |
| 277 | #expect(body["stdin"] as? String == "because 5xx is transient") |
277 | #expect(body["stdin"] as? String == "because 5xx is transient") |
| 278 | } |
278 | } |
| 279 | } |
279 | } |