Commit be7cec8be9
be7cec8be969dd3cf782764c13f76000a3dc40a7
parent: b889230698
Verified · cmc
cmc <hello@cleberg.net> · 2026-08-27T06:41:49Z
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
gitbay/Issues/IssueDetailViewModel.swift
+2 −1
| @@ -32,7 +32,8 @@ final class IssueDetailViewModel { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 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 | 39 | func close() async { |
gitbay/MRs/MRDetailViewModel.swift
+4 −3
| @@ -59,8 +59,9 @@ final class MRDetailViewModel { |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | func comment(_ text: String) async { |
| 62 | | // Long text goes in stdin, the CLI's --file - discipline. |
| 63 | | await perform(["mr", "comment"] + ref, stdin: text) |
| 62 | // Long text travels in stdin, but the server only reads it when |
| 63 | // argv says so: --file - is required, not implied. |
| 64 | await perform(["mr", "comment"] + ref + ["--file", "-"], stdin: text) |
| 64 | 65 | } |
| 65 | 66 | |
| 66 | 67 | func merge(strategy: String? = nil) async { |
| @@ -79,7 +80,7 @@ final class MRDetailViewModel { |
| 79 | 80 | |
| 80 | 81 | func reply(to thread: ReviewThread, _ text: String) async { |
| 81 | 82 | await perform( |
| 82 | | ["mr", "diff-comment"] + ref + ["--reply", String(thread.id)], |
| 83 | ["mr", "diff-comment"] + ref + ["--reply", String(thread.id), "--file", "-"], |
| 83 | 84 | stdin: text |
| 84 | 85 | ) |
| 85 | 86 | } |
gitbayTests/IssueBuildViewModelTests.swift
+1 −1
| @@ -87,7 +87,7 @@ struct IssueDetailViewModelTests { |
| 87 | 87 | let write = stub.seen[1] |
| 88 | 88 | #expect(write.method == "POST") |
| 89 | 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 | 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 | 229 | let write = stub.seen[3] |
| 230 | 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 | 232 | #expect(body["stdin"] as? String == "long review text\nwith lines") |
| 233 | 233 | } |
| 234 | 234 | |
| @@ -273,7 +273,7 @@ struct MRDetailViewModelTests { |
| 273 | 273 | let write = stub.seen[3] |
| 274 | 274 | let body = try #require(try JSONSerialization.jsonObject(with: write.body) as? [String: Any]) |
| 275 | 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 | 277 | #expect(body["stdin"] as? String == "because 5xx is transient") |
| 278 | 278 | } |
| 279 | 279 | } |